2010-12-11 18 views
1

Wie kann ich eine Funktion schreiben, die logisch und funktioniert zwischen den Elementen der Liste?Haskell IO Bool fold Frage

Ich habe dies geschrieben:

iand :: [IO Bool] -> IO Bool 

iand [] = return (True) 
iand (x:xs) = do 
    a <- x 
    b <- iand(xs) 
    return (a && b) 

Aber das scheint unconscice zu sein.

Wie kann diese Funktion mit foldM (liftM) umgeschrieben werden?

Vielen Dank.

Antwort

10

Die Prelude Funktion and :: [Bool] -> Bool fast tut, was Sie wollen, aber es ist nicht monadischen. Um eine Einargumentfunktion in eine Monade zu heben, benötigen Sie im Allgemeinen Control.Monad's liftM :: Monad m => (a -> b) -> m a -> b a; Um jedoch allgemeiner zu sein, können Sie die Prelude fmap :: Functor f => (a -> b) -> f a -> f b verwenden. Alle Monaden sind Funktoren , also ist das in Ordnung. So können Sie

fand' :: Functor f => f [Bool] -> f Bool 
fand' = fmap and 

jedoch verwenden, mindestens 90% der Zeit, würde ich schreiben, genau das Inline als fmap and xs oder wahrscheinlicher and <$> xs, Control.Applicative die mit <$> Synonym für fmap.

Natürlich, wie Sie sicher bemerkt haben, ist dies nicht das, was Sie wollen. Dafür brauchst du das Prelude sequence :: Monad m => [m a] -> m [a]. Sie haben nun eine Funktion [m a] -> m [a], und eine Funktion f [Bool] -> f Bool, so können wir diese kombinieren:

mand :: Monad m => [m Bool] -> m Bool 
mand = liftM and . sequence 

Ich wechselte zu liftM von fmap weil, obwohl fmap ‚s‚schöner‘in gewissem Sinne wäre es eine zusätzliche Functor m zu verhängen Zwang. Das sollte nicht ein Problem sein, aber es könnte aus historischen Gründen sein, also habe ich es sicher gespielt.

Sie könnten auch fragen: "Wie hätte ich jemals über sequence gewusst?" Die Antwort darauf ist der wunderbare Hoogle, mit dem Sie nach Haskell-Funktionen mit dem Namen oder suchen können. Also, seit Sie über liftM :: Monad m => (a -> b) -> m a -> m b wussten, haben Sie vielleicht erkannt, dass Sie etwas wie Monad m => [m a] -> m [a] benötigen; Hoogling für das does indeed turn up sequence.


1: Oder zumindest sollten sie jedoch aus historischen Gründen, sei-denn dies nicht immer der Fall ist.

+0

Danke!Aber sagt: "Der erwartete Typ' m 'konnte nicht mit dem abgeleiteten Typ' [] '"mit der Funktion mand verglichen werden. Was ist das Problem dort? – 4DA

+0

@Dmitry: Ups, das liegt daran, dass ich getyped. Ich behauptete, dass "mand :: Monad m => m [Bool] -> m Bool", was offensichtlich dumm ist, da der * Punkt * dieser Übung darin bestand, dir eine Funktion vom Typ 'Monad m => [m Bool ] -> m Bool'. Wenn Sie diese Art der Assertion beheben, funktioniert alles. Ich habe meine Antwort entsprechend bearbeitet. –

1

Wäre das nicht iand list = foldl (&&) True list?

+0

Nein. Das wäre eine Funktion des Typs '[Bool] -> Bool', die sich wie normale' und' verhält, aber weniger faul ist. Was Dmitry will ist eine Funktion vom Typ '[IO Bool] -> IO Bool'. – sepp2k

+0

Rechts. Verpasst das. Entschuldigung für die Verwirrung. –

2

können Sie liftM verwenden and zu drehen (die [Bool] -> Bool Typ hat) in eine Funktion vom Typ IO [Bool] -> IO Bool und sequence zu Ihrem [IO Bool] in eine IO [Bool] zu drehen.

So Ihre Funktion wird:

iand ibs = liftM and (sequence ibs)