@ Giải pháp của Cirdec chắc chắn hoạt động nhưng có vấn đề có thể xảy ra: Tổ chức này nằm sâu bên trái. Đối với nhiều (nhưng không phải tất cả!) Monads, điều này có thể cung cấp cho blowup stack tương tự như khi sử dụng không nghiêm ngặt foldl
. Vì vậy, tôi sẽ trình bày một giải pháp khác, thay vào đó hãy thay thế >>=
s. Đối với các monads như IO
, điều này sẽ cho phép hành động được xây dựng và tiêu thụ một cách uể oải từ bản đồ khi nó được thực hiện.
Giải pháp này có thể phức tạp hơn một chút, vì nó sử dụng ngay gấp để xây dựng hàm monadic mà cuối cùng sẽ tiêu thụ giá trị bắt đầu. Ít nhất tôi đã có một số rắc rối nhận được các loại quyền.
Trừ trường hợp xử lý khóa, đây thực chất là phương pháp giống như được sử dụng bởi Data.Foldable.foldlM
.
-- Pragma needed only to give f' a type signature for sanity. Getting it
-- right almost took a piece of mine until I remembered typed holes.
{-# LANGUAGE ScopedTypeVariables #-}
import Data.Map
foldlWithKeyM
:: forall m a k b. Monad m => (a -> k -> b -> m a) -> a -> Map k b -> m a
foldlWithKeyM f start m = foldrWithKey f' return m $ start
where
f' :: k -> b -> (a -> m a) -> (a -> m a)
f' k b a2mb a = f a k b >>= a2mb
Nguồn
2015-04-04 18:13:27
Tương đương bạn có thể không chỉ bọc đơn lẻ trong 'ContT' chỉ cho chức năng này? – luqui
@luqui Tôi không nghĩ rằng điều đó khá tương đương, với một nếp gấp bên trái, bạn vẫn sẽ * xây dựng * toàn bộ hành động lồng nhau trước khi 'ContT' có thể chuyển đổi nó. Đặc biệt nó không thể lười biếng khi tiêu thụ. –