【问题标题】:Recursive function parameters递归函数参数
【发布时间】:2016-07-22 09:17:35
【问题描述】:

我做了一个简单的递归函数,并期望它可以工作(但它没有):

open System
open System.Threading

let f =
    let r = Random()
    let rec d =
        printfn "%d" (r.Next())
        Thread.Sleep(1000)
        d
    d
f

在 Intellisense 的帮助下,我最终得到了以下工作功能(但不明白为什么以前的功能不起作用):

open System
open System.Threading

let f : unit =
    let r = Random()
    let rec d() =
        printfn "%d" (r.Next())
        Thread.Sleep(1000)
        d()
    d()
f

那么为什么我需要明确声明unit()

【问题讨论】:

    标签: recursion f# functional-programming


    【解决方案1】:

    在第一个版本中,您声明了一个递归对象 (let rec d) 或一个值。你是说d 对象是递归的,但是一个对象怎么可能是递归的呢?它如何称呼自己?当然,这没有意义。

    在 F# 中无法使用递归对象,这就是您的第一个版本无法工作的原因。

    在第二个版本中,您声明了一个递归函数 (let rec d())。添加(),您明确指出d 是一个函数。 此外,您通过unit 明确指出,函数f(仅调用一次)不会返回任何内容,或者,至少,您是说f 将返回一个非特定类型的值。在 F# 中,即使是最简单的函数也必须始终返回一个值。

    在您的情况下,F# 将尝试推断 f 将返回的类型。因为没有特定的类型注释并且您的 f 没有执行将使用特定类型返回特定值的操作(如计算),所以 F# 编译器会将通用返回类型分配给 f,但您的代码仍然模棱两可,您必须指定 unit 类型(F# 函数可以返回的最简单类型)才能更具体。

    值限制错误确实与F#强大的类型推断有关。请查看this interesting article 了解此错误。

    【讨论】:

      【解决方案2】:

      在您的第一次尝试中,您定义的不是一个函数,而是一个d 的值是根据自身定义的——也就是说,要知道d 是什么,您首先需要知道d 是什么。难怪它不起作用!

      为了更清楚一点,我会指出您的定义与此相同:

      let x = x
      

      你认为这会奏效吗?

      在您的第二次尝试中,您为d 提供了一个参数。是参数使它成为 function 而不是值。比较:

      let rec x() = x()
      

      这在执行时仍然会导致堆栈溢出,但至少它会编译:它是一个无条件调用自身的函数。

      您不必专门给它一个unit 参数,任何参数都可以。您可以将其设为数字​​、字符串,甚至是泛型类型。只是unit 是您不在乎它是什么时最简单的选择。

      而且您实际上不需要使用类型注释 f。这是一个无关紧要的步骤。

      最后,我想指出,即使在您的第二个代码块中,f 仍然是一个,而不是一个函数。实际上,这意味着f 中的代码将只执行一次,当f 被定义时,而不是每次你提到f 作为其他表达式的一部分,这显然是你直觉所期望的。

      【讨论】:

      • And you didn't actually need to annotate f with a type. That was an extraneous step. 但是如果没有这个无关的步骤(如果一切都正确的话),它仍然会抛出一个错误:值限制。值 'f' 已被推断为具有泛型类型 val f : '_a >要么将 'f' 定义为简单的数据项,使其成为具有显式参数的函数,或者,如果您不打算使其成为泛型,则添加类型注释。
      • 你说得对,我忘了价值限制。但是如果你把f 变成一个函数,那么这个问题无论如何都会消失。
      • 如果您创建f() 然后调用它(其他一切都正确),它仍然会抛出这个Value restriction 异常。所以似乎唯一的出路是明确声明unit。但仍然感谢您的回答,他们都非常有帮助。
      猜你喜欢
      • 2014-02-07
      • 2022-01-07
      • 2021-01-08
      • 2014-01-15
      • 1970-01-01
      • 1970-01-01
      • 2017-10-14
      • 2014-04-27
      相关资源
      最近更新 更多