2016-04-20 13 views
2
unter Verwendung von Sequenz

Ich bin derzeit versucht, die 20 Intermediate Haskell Excercises excercises und bin stecken zu lösen, die mapM umzusetzen versuchen (die moppy im excercise ist) ohne die Verwendung von sequence.MAPM zu implementieren, ohne

Alles, was ich produzieren kann, ist ein [m b] durch einfache fmap Anwendung, aber ich weiß nicht, wie es weitergeht:

moppy :: [a] -> (a -> m b) -> m [b] 
moppy la f = furry' f la -- how do I transform [m b] to m [b] without sequence 

Kann jemand mir einen Tip geben, in welcher Richtung zu suchen?

+0

Im Allgemeinen, wenn Sie jemals mehr „Kontext“ als 'map' hinzufügen möchten Sie können entweder eine Falte oder eine explizite Rekursion verwenden, um Ihre Datenstruktur zu durchlaufen. – badcook

Antwort

6

In der modernen Ära, als Benjamin Hodgson erwähnt, sollten wir sein mit Applicative für diesen besonderen Zweck:

myMapM :: Applicative f 
     => (a -> f b) -> [a] -> f [b] 

Wir myMapM f [] wollen pure [] (es gibt keine Art, wie wir alle b s erhalten können!) Sein, so

myMapM f [] = pure [] 

Nun kommen wir zum Kern der Sache, die rekursive Schritt herauszufinden. Wir wollen myMapM f (x : xs)f x durchführen, myMapM f xs durchführen und die Ergebnisse kombinieren. So

myMapM f [] = pure [] 
myMapM f (x : xs) = (:) <$> f x <*> myMapM f xs 

Wenn sie mit einer Liste etwas schön und regelmäßig tun, können wir sehr oft weg mit nur foldr:

myMapM f = foldr go (pure []) where 
    go x r = (:) <$> f x <*> r 
+0

Für echte Unergründlichkeit, '' myMapM = ('foldr' pur []). (((<*>). Fmap (:)).) '' – dfeuer

2

gut ich weiß nicht, wie dies zu tun, ohne zu viel Spoiler - so hier Sie mit einer sehr grundlegenden/rekursive Definition gehen:

moppy :: Monad m => [a] -> (a -> m b) -> m [b] 
moppy [] _ = return [] 
moppy (x:xs) f = do 
    y <- f x 
    ys <- moppy xs f 
    return (y:ys) 

es eher selbsterklärend sein sollte - bitte beachten Sie, dass Sie benötigen die Monad m Beschränkung (ich glaube, Sie es so wie man will, wie es ist ziemlich unmöglich, ohne es bekommen;))

+2

Sie brauchen nur 'Applicative m' zu schreiben' mapM' (aka 'traverse'). 'Traverse f (x: xs) = (:) <$> fx <*> Traverse f xs' –

+0

@BenjaminHodgson sagte dir, es ist * basic * - IMO ist es ein bisschen problematisch, jemanden über' Traversable' zu ​​erzählen, wenn sie mit Monaden kämpfen (und ich denke die meisten können 'do'-Notationen handhaben, da sie vertraut-imperativ erscheinen - aber warum fügst du das nicht als nette Antwort hinzu? – Carsten

2

Vielleicht hilft es, wenn Sie mit der Umsetzung mapM mit nur >>= und return starten.

mapM' :: Monad m => (a -> m b) -> [a] -> m [b] 
mapM' _ []  = return [] 
mapM' f (x:xs) =  f x   >>= 
       \y -> mapM' f xs >>= 
       \ys -> return (y:ys) 

Diese Art der gibt Ihnen die Antwort wie die vorherige Plakat erwähnt: Sie würden mit etwas ähnlich beenden. Alles, was Sie tun müssen, ist die Reihenfolge der Argumente ändern:

moppy :: (Misty m) => [a] -> (a -> m b) -> m [b]  
moppy []  _ = unicorn [] 
moppy (x:xs) f = banana (\y -> banana (\ys -> unicorn (y:ys)) (moppy xs f)) (f x) 

Oder:

moppy :: (Misty m) => [a] -> (a -> m b) -> m [b]  
moppy []  _ = unicorn [] 
moppy (x:xs) f = (\y -> (\ys -> unicorn (y:ys)) `banana` moppy xs f) `banana` f x 

Oder:

moppy :: (Misty m) => [a] -> (a -> m b) -> m [b]  
moppy []  _ = unicorn [] 
moppy (x:xs) f = let g y = let h ys = unicorn (y : ys) 
          in h `banana` moppy xs f 
        in g `banana` f x 
Verwandte Themen