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

oct*_*bus 1 f# seq

在这篇SO 帖子中,添加

 inSeq 
    |> Seq.length
    |> printfn "%d lines read"
Run Code Online (Sandbox Code Playgroud)

导致inSeq中的延迟序列被读入.

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

当Visual Studio(2012)调试器到达时

inSeq |> Seq.iter (fun x -> printfn "%A" x)
Run Code Online (Sandbox Code Playgroud)

读取过程重新开始.当我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
Run Code Online (Sandbox Code Playgroud)

我在某处读过懒惰评估的结果没有被缓存.那是怎么回事?如何缓存结果?

Fyo*_*kin 8

序列不是项目的"容器",而是在未来某个时间交付项目的"承诺".您可以将其视为您调用的函数,除非它以块的形式返回结果,而不是一次性返回.如果您调用该函数一次,它会返回一次结果.如果你第二次打电话,它会第二次返回结果.

因为你的特定序列不纯,你可以将它与非纯函数进行比较:你调用它一次,它返回一个结果; 你第二次称它,它可能会返回不同的东西.

第一次读取后,序列不会自动"记住"它们的项目 - 与第一次调用后函数不会自动"记住"它们的结果完全相同.如果你想从函数中获取它,你可以将它包装在一个特殊的"缓存"包装器中.所以你也可以做一个序列.

"缓存返回值"的一般技术通常称为" memoization ".特别是对于F#序列,它在Seq.cache函数中实现.