Verwirrung über currying und Punkt freien Stil in Haskell
Frage
Ich habe versucht, die Funktion zu implementieren
every :: (a -> IO Bool) -> [a] -> IO Bool
, die das Thema diese Frage . Ich habe versucht, dieses ohne explizite Rekursion zu tun . Ich kam mit dem folgenden Code oben
every f xs = liftM (all id) $ sequence $ map f xs
Meine Funktion funktionierte nicht, da sie nicht faul waren (was in der Frage erforderlich war), so dass kein upvotes es: -).
Allerdings habe ich noch nicht beendet. Ich habe versucht, die Funktion Punkt frei zu machen, so dass es kürzer sein würde (und vielleicht sogar Kühler). Da die Argumente f
und xs
sind die letzten, die in dem Ausdruck, den ich sie nur fallen gelassen:
every = liftM (all id) $ sequence $ map
Aber das hat nicht funktioniert, wie erwartet, in der Tat ist es überhaupt nicht arbeiten:
[1 of 1] Compiling Main ( stk.hs, interpreted ) stk.hs:53:42: Couldn't match expected type `[m a]' against inferred type `(a1 -> b) -> [a1] -> [b]' In the second argument of `($)', namely `map' In the second argument of `($)', namely `sequence $ map' In the expression: liftM (all id) $ sequence $ map Failed, modules loaded: none.
Warum ist das so? Ich hatte den Eindruck, dass es möglich war, einfach Funktionsargumente fällt nachlauf, die im Grunde ist das, was currying geht.
Lösung
Die Definition von $ ist
f $ x = f x
Lassen Sie uns voll parenthesize Ihre Funktion:
every f xs = (liftM (all id)) (sequence ((map f) xs))
und Ihre curried Version:
every = (liftM (all id)) (sequence map)
Wie Sie bemerkt, sind diese nicht identisch. Sie können nur Funktionsargumente Hinter fallen, wenn sie das letzte, was angelegt sind. Zum Beispiel:
f x = g c x
ist eigentlich
f x = (g c) x
und die Anwendung von (g c) bis x kommt zuletzt, so können Sie schreiben
f = g c
Ein Muster mit der Anwendung Operator $ ist, dass es oft die Zusammensetzung Operator wird. in Punkten freien Versionen. Dies liegt daran,
f $ g $ x
entspricht
(f . g) $ x
Beispiel:
every f xs = liftM (all id) $ sequence $ map f xs
kann sich
every f xs = (liftM (all id) . sequence . map f) xs
an welcher Stelle Sie xs fallen können:
every f = liftM (all id) . sequence . map f
Die Beseitigung der Argument f ist schwieriger, weil sie vor der Zusammensetzung Operator angewendet wird. Lassen Sie uns die Definition von Punkt benutzen http://www.haskell.org/haskellwiki/Pointfree :
dot = ((.) . (.))
Mit Punkten, das ist
(f `dot` g) x = f . g x
und ist genau das, was wir alle voll Punkte frei machen müssen:
every = (liftM (all id) . sequence) `dot` map
Leider aufgrund von Einschränkungen in dem Haskell Typ-System, das man braucht eine explizite Art Signatur:
every :: (Monad m) => (a -> m Bool) -> [a] -> m Bool