这是我在 SO 上的第一篇文章,而且我对 Haskell 还比较陌生,所以请原谅任何失误或者我的代码不是惯用的!
考虑以下两个直观的描述:a, f(a), f(f(a))...
A. 一个列表,包含:a、f 对 a 的应用、f 对那个的应用、f 对那个的应用……
B. 一个列表,在第 i 个位置包含 f 到 a 的 i 个嵌套应用程序。
我的问题是我试图使用iterate
Haskell 中的函数来做A被烧毁了。我的真实应用程序是一个模拟,但下面的人为示例突出了这个问题。
import Control.Monad.State
example :: State Int [[String]]
step :: [String] -> State Int [String]
step l = do
currentState <- get
let result = if (currentState == 1)
then "foo":l
else "bar":l
put (currentState + 1)
return result
example = do
sequence $ take 3 . iterate (>>= step) $ return []
有了这些定义,
evalState example 1
结果是:
[[],["foo"],["bar","bar"]]
显然,iterate
是B,而不是A!因为该step
函数只会在输入列表中添加一些内容,所以无论状态如何,step ["foo"]
都不可能导致!["bar", "bar"]
让我说我确实理解这里发生了什么,而且 - 正式 - 结果正是“应该是”:step
是一个有状态的函数,所以当 f(a) 作为 f( f(a)),它将被重新计算,而不是从第二个列表项中取出,因为状态已经改变。我也意识到我可以通过将我的累积列表放入状态中来避免在我的实际应用程序中发生这种情况。
尽管如此,发布此内容有两个原因。
首先,重点iterate
是经常以一种可能误导初学者认为它是A的方式来解释它,而实际上它是B。这包括Learn You A Haskell(否则我发现它非常有用),但也可以在 SO 上发布(例如, here和here)。事实上,iterate
LYAHFGG 中的口头解释几乎就是上面的定义A。因此,在此发布一个帖子可能是有用的,作为其他 Haskell 新手的资源,他们因此而遇到错误并正在寻找解释(所以一定要发布更准确、技术性、措辞更好的澄清A和A的区别B下)。
其次,我仍然会对是否有一个实际上会执行A的函数感兴趣!换句话说,在上面的有状态示例中,我如何生成列表(稍微滥用符号):[a, b = f(a), f(b), ...]?换句话说,给定
example2 = do
firstResult <- step []
secondResult <- step firstResult
return $ [[], firstResult, secondResult]
为此
evalState example2 1
产生预期的结果
[[],["foo"],["bar","foo"]]
我怎样才能重写example2
使用iterate
?
在初学者 Haskell 列表中,发布了一个有关记忆版本的相关问题iterate
。但是,该查询似乎没有收到答案。
我不完全确定懒惰真的是我的应用程序中的问题。一个严格的版本会iterate
做我想要的吗?我自己的,天真的,如下所示的“严格迭代”似乎没有任何区别。
iterate' f x = x : rest
where previous = f x
rest = previous `seq` iterate f previous
任何有关这一切的见解将不胜感激!