理解哈斯克尔的懒惰(折叠)

  • 本文关键字:折叠 哈斯克 haskell
  • 更新时间 :
  • 英文 :


我有一个键值对[(k, v)]的无限列表,我想创建一个从该列表派生的查找函数k -> v。当列表是有限的时,使用foldl可以很容易地做到这一点,但对于无限列表来说,这似乎更复杂。请考虑下面的代码。用createMapCustom创建的查找终止,而用createMapFoldl创建的查找不终止。有什么办法可以让后者终止吗?

main :: IO ()
main = do
let infList = map (k -> (k, "value")) [0..]
print $ createMapCustom infList 0
print $ createMapFoldl infList 0
createMapCustom, createMapFoldl :: Eq k => [(k, v)] -> (k -> Maybe v)
createMapCustom [] _ = Nothing
createMapCustom ((k, v):xs) k'
| k == k'   = Just v
| otherwise = createMapCustom xs k'
createMapFoldl = foldl (f ~(k, v) -> f `combine` (k' -> if k' == k then Just v else Nothing)) (const Nothing)
combine :: (a -> Maybe b) -> (a -> Maybe b) -> (a -> Maybe b)
combine f1 f2 v = case f1 v of
Just x  -> Just x
Nothing -> case f2 v of
Just x2 -> Just x2
Nothing -> Nothing

这篇文章很好地解释了这一点https://www.reddit.com/r/haskell/comments/qrf54/why_does_foldr_work_on_infinite_lists_but_not/

与其使用foldl,我应该使用foldr,因为它是正确的主动

createMapFoldr = foldr ((k, v) f -> (k' -> if k' == k then Just v else Nothing) `combine` f) (const Nothing)

最新更新