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

时间:2016-09-27 18:50:04

标签: f# seq

在此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

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

1 个答案:

答案 0 :(得分:8)

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

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

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

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