2012-03-13 23 views
13

Với hai monads, Monad mMonad n, tôi muốn chuyển đổi m (n a) thành n (m a). Nhưng dường như không có cách nào chung vì cả hai giao dịch (>>=)return chỉ có một loại đơn vị và mặc dù (>>=) cho phép trích xuất nội dung từ một đơn vị, bạn phải đóng gói lại thành cùng một loại đơn nguyên để có thể là giá trị kết quả.Đóng gói lại các monads - bất kỳ cách thức chung nào?

Tuy nhiên, nếu chúng tôi đặt m thành loại cố định, công việc trở nên dễ dàng. Hãy Maybe làm ví dụ:

reorder :: (Monad n) => Maybe (n a) -> n (Maybe a) 
reorder Nothing = return Nothing 
reorder (Just x) = do 
    x' <- x 
    return $ Just x' 

Hoặc một danh sách:

reorder :: (Monad n) => [n a] -> n [a] 
reorder [] = return [] 
reorder (x:xs) = do 
    x' <- x 
    xs' <- reorder xs 
    return (x':xs') 

Không khó để thấy, chúng tôi đã có một mô hình ở đây. Để được rõ ràng hơn, hãy viết nó trong một cách Applicative, và nó không có gì hơn việc áp dụng các nhà xây dựng dữ liệu cho mỗi phần tử:

reorder (Just x) = Just <$> x 
reorder (x:xs) = (:) <$> x <*> (reorder xs) 

Câu hỏi của tôi là: làm một typeclass Haskell đã tồn tại để mô tả các hoạt động đó, hay tôi phải tự mình phát minh ra bánh xe?

Tôi đã tìm kiếm ngắn gọn trong tài liệu GHC và không thấy gì hữu ích cho chủ đề này.

Trả lời

14

Data.Traversable cung cấp những gì bạn đang tìm kiếm:

sequenceA :: (Traversable t, Applicative f) => t (f a) -> f (t a) 

GHC thậm chí cung cấp hỗ trợ cho các trường hợp tự động phát sinh:

{-# LANGUAGE DeriveFunctor, DeriveFoldable, DeriveTraversable #-} 
import Data.Foldable 
import Data.Traversable 

data List a = Nil | Cons a (List a) 
    deriving(Functor, Foldable, Traversable) 
+0

Điều này, tất nhiên, chỉ hoạt động khi hàm tạo bên ngoài của bạn là một 'Traversable' (không phải tất cả' Monad 'là). Tiền thưởng là phần bên trong chỉ phải là 'Áp dụng'. –

5

Một tìm kiếm nhanh trên hoogle cho (Monad m, Monad n) => m (n a) -> n (m a) chỉ cho tôi rằng có một số chức năng mà (gần) tuân thủ chữ ký bạn đang tìm kiếm:

  1. Data.Traversable.sequence :: (Traversable t, Monad m) => t (m a) -> m (t a);
  2. Data.Traversable.sequenceA :: Applicative f => t (f a) -> f (t a);
  3. Contro.Monad.sequence :: Monad m => [m a] -> m [a] (cũng được xuất bởi Prelude).

Cả [a]Maybe a là trường hợp của traversable, vì vậy chức năng sắp xếp lại của bạn chỉ là các ứng dụng của Data.Traversable.sequence. Người ta có thể viết, trong ví dụ:

ghci> (Data.Traversable.sequence $ Just (return 1)) :: IO (Maybe Int) 
Just 1 
it :: Maybe Int 

ghci> (Data.Traversable.sequence $ Just ([1])) :: [Maybe Int] 
[Just 1] 
it :: [Maybe Int] 

ghci> (Data.Traversable.sequence $ [Just 1]) :: Maybe [Int] 
Just [1] 
it :: Maybe [Int] 

Xin lưu ý tuy nhiên đó việc khai báo lớp học cụ thể là class (Functor t, Foldable t) => Traversable t, và nếu bạn cũng nhìn vào các loại của hai chức năng khác, nó không có vẻ như những gì bạn đang tìm kiếm có thể được thực hiện theo cách tổng quát cho tất cả các mon mn mà không có giới hạn/điều kiện tiên quyết.

1

Không phải tất cả Monads đều có thể đi làm theo cách đó. distributive gói Edward Kmett cung cấp một typeclass Distributive cho loại cấu trúc cho là tương tự như những gì bạn mong muốn (giản thể):

class Functor g => Distributive g where 
    distribute :: Functor f => f (g a) -> g (f a) 
    collect  :: Functor f => (a -> g b) -> f a -> g (f b) 

Mặc định nghĩa được cung cấp cho distributecollect, viết về nhau.Tôi đã tìm thấy gói này theo số searching hayoo for the desired type signature.

4

Nó không thể được thực hiện nói chung: một ví dụ tốt về một đơn nguyên mà không thể làm điều này là độc giả (hoặc chức năng) monad. Điều đó sẽ đòi hỏi các chức năng sau đây để có thể định nghĩa:

impossible :: (r -> IO a) -> IO (r -> a) 

Nó không phải đơn giản để chứng minh rằng một hàm không thể được thực hiện. Nhưng theo trực giác, vấn đề là bất cứ điều gì IO phải được thực hiện trong giá trị trả lại phải được thực hiện trước khi chúng tôi biết những gì các thông số r. Vì vậy, impossible readFile sẽ phải cung cấp chức năng thuần túy FilePath -> String trước khi nó biết tệp nào sẽ mở. Rõ ràng, ít nhất, impossible không thể làm những gì bạn muốn.

Các vấn đề liên quan