2015-04-04 15 views
6

Tôi đang tìm một hàm giống như foldlWithKey, nhưng được đóng gói trong một đơn nguyên.foldlWithKey in monad

Tôi mong chờ nó có loại

Monad m => (a -> k -> b -> m a) -> a -> Map k b -> m a 

nhưng Hoogle không đem lại cho tôi bất cứ điều gì với loại đó.

Trả lời

10

foldlWithKey đã rất gần với những gì bạn muốn. Nếu bạn chuyên a đến m a, bạn sẽ có thứ gì đó hoạt động trên các giá trị được đóng gói trong một đơn nguyên.

foldlWithKey :: ( a -> k -> b -> a) -> a -> Map k b -> a 
foldlWithKey :: (m a -> k -> b -> m a) -> m a -> Map k b -> m a 
      {- ^- you don't want these -^ -} 

Chúng ta có thể thoát khỏi hai m a s bạn không muốn với >>=return.

foldlWithKeyM :: Monad m => (a -> k -> b -> m a) -> a -> Map k b -> m a 
foldlWithKeyM f acc = foldlWithKey f' (return acc) 
    where 
     f' ma k b = ma >>= \a -> f a k b 
7

@ 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 
+0

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

+0

@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ụ. –