F#如何编写一个按顺序提供计数器编号的函数

时间:2013-08-11 04:37:41

标签: f#

因此,如果你去银行,有一个设备可以从中提取数字。

我想写一个这样的函数。因此,每次调用此函数时,我们都会得到系列中的下一个数字。

因此,如果第一次调用此函数,我们得到1.第二次得到2 ....依此类推。

这是我到目前为止所写的内容

let X =
    let myseq = seq {1 .. 100}
    let GetValue = 
        Seq.head (Seq.take 1 myseq)
    GetValue;;

 let p = X;;
 p;;
 p;;
 p;;

但它总是返回1.我的希望是因为序列是一个闭包,每次我拿一个,我会得到下一个数字。

我也试过这个

let X =
    let mutable i = 1
    let GetValue = 
        i <- i + 1
        i
    GetValue;;

 let p = X;;
 p;;
 p;;
 p;;

这只打印2 ...

3 个答案:

答案 0 :(得分:7)

您必须返回一个功能。对此,你必须每次传递一些东西,即你的+1必须推迟。

let factory = 
    let counter = ref 0
    fun () -> 
        counter.Value <- !counter + 1
        !counter

现在你得到了

> factory();;
val it : int = 1
> factory();;
val it : int = 2
这样做有很好的副作用,你完全隐藏了函数内部的可变参考单元格,因此无法以某种方式篡改你的计数器。

答案 1 :(得分:7)

仅供参考,如果您想要一个使用序列的版本(就像问题中的第一种方法一样),您可以使用IEnumerable界面执行此操作:

let factory = 
  // Infinite sequence of numbers & get enumerator
  let numbers = Seq.initInfinite id
  let en = numbers.GetEnumerator()
  fun () -> 
    // Move to the next number and return it
    en.MoveNext() |> ignore
    en.Current

在Daniel的回答中,它与factory的行为相同。这仍然使用可变状态 - 但它隐藏在枚举器中(它保持序列的当前状态在MoveNext次调用之间)。

在这个简单的例子中,我会使用Daniel的版本,但如果你想迭代其他东西而不仅仅是增加数字,上面的内容可能很方便。

答案 2 :(得分:5)

您需要在声明之外移动变量。您还需要声明一个函数,以便在每次调用它时对其进行求值。

let mutable i = 1
let X() =
    i <- i + 1
    i

这确保了每次调用函数并且变量正确递增。