我想要製作一個通用函數,可以在各種輸入上進行摺疊(請參閱Making a single function work on lists, ByteStrings and Texts (and perhaps other similar representations))。由於one answer suggested,ListLike只是爲此。它的FoldableLL類定義了一個可摺疊的抽象。但是,我需要一個單一的摺疊。所以我需要根據foldl
/foldr
來定義foldM
。如何使用foldr/foldl定義foldM(如果可能的話)?
到目前爲止,我的嘗試失敗了。我試圖定義
foldM'' :: (Monad m, LL.FoldableLL full a) => (b -> a -> m b) -> b -> full -> m b
foldM'' f z = LL.foldl (\acc x -> acc >>= (`f` x)) (return z)
但是它在大輸入上運行內存不足 - 它構建了一個很大的未計算的計算樹。例如,如果我傳遞一個大文本文件到
main :: IO()
main = getContents >>= foldM'' idx 0 >> return()
where
-- print the current index if 'a' is found
idx !i 'a' = print i >> return (i + 1)
idx !i _ = return (i + 1)
它吃掉所有內存並失敗。
我有一種感覺,問題是單子計算的順序是錯誤的 - 例如((... >>= ...) >>= ...)
而不是(... >>= (... >>= ...))
,但到目前爲止我還沒有找到如何解決這個問題。
解決方法:由於ListLike
暴露mapM_
,我就ListLike
S按包裝累加器進入狀態單子構建foldM
:
modifyT :: (Monad m) => (s -> m s) -> StateT s m()
modifyT f = get >>= \x -> lift (f x) >>= put
foldLLM :: (LL.ListLike full a, Monad m) => (b -> a -> m b) -> b -> full -> m b
foldLLM f z c = execStateT (LL.mapM_ (\x -> modifyT (\b -> f b x)) c) z
雖然這適用於大型數據集精緻,它不是很不錯。如果可以在FoldableLL
(沒有mapM_
)的數據上定義它,它不會回答原始問題。
爲什麼不從'Control.Monad'使用'foldM'?還可以使用嚴格版本'foldl''而不是'foldl'。 – Satvik
@Satvik因爲我需要它不僅定義列表,而且定義任何[FoldableLL](http://hackage.haskell.org/packages/archive/ListLike/3.1.6/doc/html/Data-ListLike-FoldableLL。 HTML),它只暴露不同類型的純摺疊,而不是單一折疊。我的不好,我沒有在帖子中說清楚 - 我已更正了類型簽名。 –
爲了以相反的順序組合計算,使用'foldr'而不是'foldl'。 – dave4420