2009-05-25 9 views
9

Ich habe versucht, die FunktionVerwirrung über currying und Punkt freien Stil in Haskell

every :: (a -> IO Bool) -> [a] -> IO Bool 

die das Thema für this question war zu implementieren. Ich habe versucht, dies ohne explizite Rekursion zu tun. Ich kam mit dem folgenden Code

every f xs = liftM (all id) $ sequence $ map f xs 

Meine Funktion hat noch nicht funktionieren, da es nicht faul war (was in der Frage erforderlich war), so gibt es kein upvotes :-).

Allerdings habe ich nicht damit aufgehört. Ich habe versucht, die Funktion point-free so zu machen, dass es kürzer wäre (und vielleicht sogar kühler). Da die Argumente f und xs die letzten, die im Ausdruck sind ließ ich sie einfach:

every = liftM (all id) $ sequence $ map 

Aber wie erwartet nicht funktioniert hat, in der Tat hat es nicht funktioniert:

 
    [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 das? Ich hatte den Eindruck, dass es einfach war, nachstehende Funktionsargumente fallen zu lassen, worum es bei Currying eigentlich geht.

Antwort

25

Die Definition von $ ist

f $ x = f x 

Lassen Sie uns voll Ihre Funktion klammern:

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 nachfolgende Funktionsargumente löschen, wenn sie zuletzt angewendet wurden. Zum Beispiel

f x = g c x 

ist eigentlich

f x = (g c) x 

und die Anwendung von (gc) bis x zuletzt kommt, so dass Sie

f = g c 

Ein Muster mit der Anwendung Operator $ schreiben können, ist dass es oft zum Kompositionsoperator wird. in punktefreien Versionen.Dies liegt daran,

f $ g $ x 

zu

(f . g) $ x 

Zum Beispiel entspricht,

every f xs = liftM (all id) $ sequence $ map f xs 

werden kann

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 

Das Entfernen des Arguments f ist schwieriger, weil es vor dem Kompositionsoperator angewendet wird. Lassen Sie uns die Definition von Punkt von http://www.haskell.org/haskellwiki/Pointfree verwenden:

dot = ((.) . (.)) 

Mit Punkten, diese

(f `dot` g) x = f . g x 

und ist genau das, was wir alle voll Punkte frei zu machen brauchen:

every = (liftM (all id) . sequence) `dot` map 

Leider Aufgrund von Einschränkungen im Haskell-Typsystem benötigt dieser eine explizite Typ-Signatur:

every :: (Monad m) => (a -> m Bool) -> [a] -> m Bool 
+2

Oder Sie können -XNoMonomorphismRestriction verwenden und den expliziten Typ sig löschen. –

+1

Argh ... die 'dot' Definition sieht aus wie jemand, der mich anstarrt. – gawi