我有一个键值对[(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)