代码之家  ›  专栏  ›  技术社区  ›  Chul-Woong Yang

困惑:Haskell IO懒惰

  •  3
  • Chul-Woong Yang  · 技术社区  · 10 年前

    我很难理解Haskell懒惰的评价。

    我编写了简单的测试程序。它读取4行数据 第二和第四输入线具有许多数字。

    consumeList :: [Int] -> [Int] -> [Int]
    consumeList [] _ = error "hi" -- to generate heap debug
    consumeList (x:xs) y = consumeList xs y   
    main = do
        inputdata <- getContents
        let (x:y:z:k:xs) = lines inputdata
            s = map (read ::String->Int) $ words $ k
            t = []
        print $ consumeList s t
    

    words map 已执行 对于懒散的字符流,这个程序使用恒定的内存。 constant memory usage

    但当我添加论点时 t ,情况发生了变化。 我的期望是 t型 地图 在懒流上, 和 t型 未用于 consumeList ,此更改不应更改 内存使用情况。但没有。

    consumeList :: [Int] -> [Int] -> [Int]
    consumeList [] _ = error "hi" -- to generate heap debug
    consumeList (x:xs) y = consumeList xs y
    main = do
        inputdata <- getContents
        let (x:y:z:k:xs) = lines inputdata
            s = map (read ::String->Int) $ words $ k
            t = map (read ::String->Int) $ words $ y
        print $ consumeList s t    -- <-- t is not used
    

    memory is increasing

    Q1)为什么当 t型 根本不使用?

    我还有一个问题。当我模式匹配懒惰流时 [,] 不 具有 (:) 存储器分配行为被改变。

    consumeList :: [Int] -> [Int] -> [Int]
    consumeList [] _ = error "hi" -- to generate heap debug
    consumeList (x:xs) y = consumeList xs y   
    main = do
        inputdata <- getContents
        let [x,y,z,k] = lines inputdata    -- <---- changed from (x:y:..)
            s = map (read ::String->Int) $ words $ k
            t = []
        print $ consumeList s t
    

    memory keeps increasing

    Q2)是 (:) [,] 在懒惰评估方面有所不同?

    欢迎任何评论。谢谢

    [编辑]

    Q3)那么,是否可以先处理第四条生产线 处理第二行,而不增加内存消耗?

    德里克指导的实验如下。 通过从第二个例子中切换y和k,我得到了相同的结果:

    consumeList :: [Int] -> [Int] -> [Int]
    consumeList [] _ = error "hi"
    consumeList (x:xs) y = consumeList xs y
    main = do
        inputdata <- getContents
        let (x:y:z:k:xs) = lines inputdata
            s = map (read ::String->Int) $ words $ y  -- <- swap with k
            t = map (read ::String->Int) $ words $ k  -- <- swap with y
        print $ consumeList s t
    

    enter image description here

    1 回复  |  直到 10 年前
        1
  •  5
  •   Derek Elkins left SE    10 年前

    为了回答你的第一个问题, t 就垃圾收集器而言,是实时的,直到您到达 consumeList .从那以后就没什么大不了的了 t型 这将是一个指向工作的笨蛋,但这里的问题是笨蛋现在一直在坚持 y 活着和 getContents 必须实际读入 y 到达 k 在第一个示例中, y 可以在读取时被垃圾收集。(作为一个实验,如果你换了 y k 在这个例子中,我想你会看到与第一个例子非常相似的行为。)

    对于第二个问题, let [x,y,z,k] = ... 意思是“(无可辩驳地)匹配 确切地 这意味着当你强迫 k 它需要(此时)检查是否没有其他元素,这意味着它需要读入对应于 k 然后才能开始处理它。在较早的情况下, let (x:y:z:k:xs) = ... 它可以开始处理 k 因为它不必首先检查 xs [] (_:_) .

    推荐文章