2013-07-10 57 views
6

tôi có mã này:Tổng quát "chuỗi" cho tất cả các functors?

fmapM :: Monad m => (a -> m b) -> (t, a) -> m (t, b) 
fmapM f (id, e) = do 
    ev <- f e 
    return (id, ev) 

mà về cơ bản áp dụng cho các chức năng để các yếu tố thứ 2 trong tuple và sau đó "chiết xuất" các đơn nguyên. Kể từ khi tuple là một functor, có cách nào để khái quát hóa điều này cho tất cả các functors? Tôi không thể nghĩ ra một thực hiện, nhưng chữ ký loại nên là:

fmapM :: (Monad m, Functor f) => (a -> m b) -> f a -> m f b 

nó sẽ có vẻ như bước 2 sẽ là một "chuỗi" hoạt động, trong đó trích xuất các đơn nguyên từ một functor (danh sách). Nhưng trình tự không được tổng quát hóa cho tất cả các functors. Bạn có thể đưa ra một triển khai chung về fmapM không?

Chỉnh sửa: Tôi đã nhận ra rằng phiên bản cũ của ôm đã thực hiện chức năng này. Tuy nhiên, tôi không thể tìm thấy mã. Bây giờ, tôi khuyên rằng tôi nên sử dụng có thể gập/di chuyển được để đạt được điều tương tự.

+0

Ah, tôi thấy 'fmapM' bạn muốn nói đến trong Hugs cũ, nhưng đó chỉ là phiên bản ít phổ biến hơn của' Traversable'. Nó vẫn là một lớp với một triển khai khác nhau cho từng loại. – shachaf

+0

(Bạn có thể lấy được 'fmap' - cũng như nhiều hàm khác - chỉ từ' đi ngang', nhưng không ngược lại.) – shachaf

Trả lời

11

Chức năng bạn đang muốn tìm traverse, từ Data.Traversable:

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

Lưu ý rằng bạn có thể không traverse bất kỳ Functor - ví dụ, (r ->) - vì vậy có một lớp con riêng của Traversable functors. Cũng lưu ý rằng bạn không cần Monad - chỉ Applicative (sự khái quát hóa này hữu ích).

+0

Việc triển khai tối thiểu Traversable cho '(,) a' sẽ giống như' sequenceA (a, b) = do {b '<- b; trả về $ (,) ab '} 'trong ký hiệu đơn điệu và' (,) a <$> b' trong ký hiệu ứng dụng ... nhưng traversable muốn '(,) a' để có thể gập lại, và điều đó dường như không thể ... – BruceBerry

+1

Có thể. Trong thực tế, nếu bạn định nghĩa 'traverse' (thay vì' sequenceA'), bạn có thể tự động viết cả một 'Functor' và một thể hiện' Foldable' bằng cách sử dụng 'fmapDefault' và' foldMapDefault' tương ứng. – shachaf

+0

'traverse' cho' (,) a' trông giống như: 'traverse f (x, y) = (,) x <$> f y'. 'foldMap' và' fmap' trông giống như: 'foldMap f (x, y) = f y'; 'fmap f (x, y) = (x, f y)'. 'traverse' là một sự khái quát hóa trực tiếp của cả hai. – shachaf