为什么这个功能没有懒惰?

cdk*_*cdk 1 haskell lazy-evaluation

我有两个类似于filter和的功能takeWhile.

filterAcc, takeWhileAcc :: ([a] -> Bool) -> [a] -> [a]
filterAcc p xs = go xs []
    where go [] acc     = acc
          go (x:xs) acc
            | p (x:acc) = go xs (x:acc)
            | otherwise = go xs acc

takeWhileAcc p xs = go xs []
    where go [] acc     = acc
          go (x:xs) acc
            | p (x:acc) = go xs (x:acc)
            | otherwise = acc
Run Code Online (Sandbox Code Playgroud)

他们都采取谓词和列表,以及他们从正规的不同filter,并takeWhile在该谓词采取累积结果作为输入.

我的问题是,虽然filter even [1..]将立即(懒惰地)开始产生输出,filterAcc (any even) [1..]挂起.我怀疑辅助函数go是阻止这些函数懒惰地运行.

如何使这些功能懒惰地运行?

ham*_*mar 6

问题是,go总是以尾部调用结束自己的利弊情形.当它到达列表的末尾时,它只返回一些有用的东西,当然这种情况永远不会发生在无限列表中.

相反,你应该随时返回元素:

filterAcc, takeWhileAcc :: ([a] -> Bool) -> [a] -> [a]
filterAcc p xs = go xs []
    where go [] acc     = []
          go (x:xs) acc
            | p (x:acc) = x : go xs (x:acc)
            | otherwise = go xs acc

takeWhileAcc p xs = go xs []
    where go [] acc     = []
          go (x:xs) acc
            | p (x:acc) = x : go xs (x:acc)
            | otherwise = []
Run Code Online (Sandbox Code Playgroud)