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

Kno*_*uch 5 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;;
Run Code Online (Sandbox Code Playgroud)

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

我也尝试过这个

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

 let p = X;;
 p;;
 p;;
 p;;
Run Code Online (Sandbox Code Playgroud)

这只打印2 ...

Dan*_*ian 8

你必须返回一个函数.而且,你必须每次都传递一些东西,即你+1必须推迟.

let factory = 
    let counter = ref 0
    fun () -> 
        counter.Value <- !counter + 1
        !counter
Run Code Online (Sandbox Code Playgroud)

现在你明白了

> factory();;
val it : int = 1
> factory();;
val it : int = 2
Run Code Online (Sandbox Code Playgroud)

这样做有很好的副作用,你完全隐藏了函数内部的可变参考单元格,因此没有办法以某种方式篡改你的计数器.


Tom*_*cek 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
Run Code Online (Sandbox Code Playgroud)

它的行为与factory丹尼尔的答案相同.这仍然使用可变状态 - 但它隐藏在枚举器内(它保持MoveNext调用之间序列的当前状态).

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


Joh*_*mer 6

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

let mutable i = 1
let X() =
    i <- i + 1
    i
Run Code Online (Sandbox Code Playgroud)

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