2013-07-10 13 views
6

mam ten kod:Generalizowanie "sekwencji" dla wszystkich funktorów?

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

które zasadniczo stosuje funkcję do 2-ej w krotce, a następnie „wyciąg” monady. Skoro krotka jest funktorem, czy istnieje sposób uogólnienia tego dla wszystkich funktorów? Nie mogę myśleć o realizacji, ale podpis typu powinny być:

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

wydaje się jak 2. etapu będzie „sekwencja” operacja, która wydobywa monady z innego funktora (listy). Ale sekwencja nie jest uogólniona na wszystkie funktory. Czy możesz wymyślić ogólną implementację fmapM?

Edytuj: Zdałem sobie sprawę, że stara wersja uścisków miała tę funkcję zaimplementowaną. Jednak nie mogę znaleźć kodu. Teraz sugeruje się, że używam składanego/przejezdnego, aby osiągnąć to samo.

+0

Ah, widzę "fmapM", które masz na myśli w starych uściskach, ale to była po prostu mniej ogólna wersja "Traversable". Wciąż jest to klasa z inną implementacją dla każdego typu. – shachaf

+0

(Możesz wyprowadzić 'fmap' - jak również wiele innych funkcji - od samego' ruchu ', ale nie odwrotnie.) – shachaf

Odpowiedz

11

Funkcja szukasz jest traverse z Data.Traversable:

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

Należy pamiętać, że nie można traverse dowolny Functor - na przykład (r ->) - więc nie ma osobny podklasa Traversable funktorów. Zauważ, że nie potrzebujesz Monad - tylko Applicative (to uogólnienie jest przydatne).

+0

Minimalna implementacja Traversalable dla '(,) a' będzie czymś w rodzaju' sekwencja A (a, b) = do {b '<- b; return $ (,) ab '} 'w monadycznej notacji i' (,) a <$> b' w notacji aplikacyjnej ... ale traversal, chce '(,) a' również być składanym, a to nie wydaje się być możliwe ... – BruceBerry

+1

Jest to możliwe. W rzeczywistości, jeśli zdefiniowałeś 'traverse' (zamiast' sequenceA'), możesz automatycznie napisać instancję 'Functor' i' Foldable' używając odpowiednio 'fmapDefault' i' foldMapDefault'. – shachaf

+0

'traverse' dla' (,) a' wygląda następująco: 'traverse f (x, y) = (,) x <$> f y'. 'foldMap' i' fmap' wyglądają następująco: 'foldMap f (x, y) = f y'; 'fmap f (x, y) = (x, f y)'. 'trawers' to bezpośrednie uogólnienie tych dwóch. – shachaf

Powiązane problemy