为什么迭代先前读入的序列会触发新的读取?

Why does iterating previously read-in sequence trigger a new read?

在此 SO post 中,添加

 inSeq 
    |> Seq.length
    |> printfn "%d lines read"

导致 inSeq 中的惰性序列被读入。

好的,我已经扩展了该代码并希望首先打印出该序列(请参阅下面的新程序)。

当 Visual Studio (2012) 调试器到达

inSeq |> Seq.iter (fun x -> printfn "%A" x)

读取过程重新开始。当我使用调试器检查 inSeq 时,inSeq 似乎没有任何元素。

如果我先将元素读入 inSeq,我如何才能看到(检查)这些元素,为什么它们不会通过调用 Seq.iter 打印出来?

open System
open System.Collections.Generic
open System.Text
open System.IO
#nowarn "40"


let rec readlines () =
    seq {
        let line = Console.ReadLine()
        if not (line.Equals("")) then
            yield line
            yield! readlines ()
}

[<EntryPoint>]
let main argv = 
    let inSeq = readlines ()

    inSeq 
    |> Seq.length
    |> printfn "%d lines read"

    inSeq |> Seq.iter (fun x -> printfn "%A" x)
    // This will keep it alive enough to read your output
    Console.ReadKey() |> ignore    
    0

我在某处读到惰性求值的结果没有被缓存。这就是这里发生的事情吗?如何缓存结果?

序列不是 "container" 项,而是 "promise" 在将来某个时间交付项。您可以将其视为您调用的一个函数,除了它 return 它的结果是分块的,而不是一次全部。如果您调用该函数一次,它会 return 给您一次结果。如果你第二次调用它,它将 return 第二次的结果。

因为你的特定序列不是纯的,你可以把它比作一个非纯函数:你调用它一次,它return就是一个结果;你第二次调用它,它可能 return 不一样。

序列在第一次读取后不会自动 "remember" 它们的项目 - 与函数在第一次调用后不会自动 "remember" 它们的结果完全相同。如果你想从一个函数中得到它,你可以把它包装在一个特殊的 "caching" 包装器中。所以你也可以为一个序列做。

"caching return value"的通用技术通常称为“memoization". For F# sequences in particular, it is implemented in the Seq.cache函数。