2015-10-11 6 views
6

Ich habe versucht, die folgende Funktionsdefinition zu machen:Warum funktioniert diese freie Definition in Haskell nicht?

relativelyPrime x y = gcd x y == 1 

Punkt frei:

relativelyPrime = (== 1) . gcd 

Jedoch gibt dies mir die folgende Fehlermeldung:

Couldn't match type ‘Bool’ with ‘a -> Bool’ 
Expected type: (a -> a) -> a -> Bool 
    Actual type: (a -> a) -> Bool 
Relevant bindings include 
    relativelyPrime :: a -> a -> Bool (bound at 1.hs:20:1) 
In the first argument of ‘(.)’, namely ‘(== 1)’ 
In the expression: (== 1) . gcd 
In an equation for ‘relativelyPrime’: 
    relativelyPrime = (== 1) . gcd 

ich nicht ganz verstehen. gcd benötigt zwei Ints/Integer, gibt einen Ints/Integer zurück, dann wird Int/Integer auf "1" auf Gleichheit überprüft. Ich sehe nicht, wo mein Fehler ist.

+4

gut 'gcd' es wird eine andere Funktion erzeugen, wenn nur ein Argument gegeben - und in Ihrem punkt- freie Version übergeben Sie diese * Funktion * an '(== 1)' die natürlich nicht mit Funktionen umgehen kann;) – Carsten

+2

vielleicht verstehen Sie, wenn Sie zuerst * einen * Punkt * entfernen: 'relativePrime x = (= = 1). gcd x' das funktioniert!Jetzt können Sie * x nicht mehr entfernen, da es * gebunden * ist, um zu 'gcd' zu fasten - Sie könnten, wenn Sie' (== 1) $ gcd x' hatten – Carsten

+1

@ Carstens Kommentar ist korrekt. Eine Option wäre, 'uncurry' zu verwenden, um' gcd' in eine Funktion mit einem Argument zu verwandeln (indem ein Tupel von zwei ganzen Zahlen genommen wird). – psmears

Antwort

7

Es funktioniert nicht, weil gcd zwei Eingänge erfordert, während die Funktionszusammensetzung nur gcd einen Eingang bereitstellt. Betrachten wir die Definition der Funktion Zusammensetzung:

f . g = \x -> f (g x) 

Daher der Ausdruck (== 1) . gcd äquivalent ist:

\x -> (== 1) (gcd x) 

Das ist nicht das, was Sie wollen. Sie wollen:

\x y -> (== 1) (gcd x y) 

Sie könnten einen neuen Operator definieren eine einstellige Funktion mit einer binären Funktion zu komponieren:

f .: g = \x y -> f (g x y) 

Dann Ihr Ausdruck wird:

relativelyPrime = (== 1) .: gcd 

In der Tat, die (.:) Operator kann in Bezug auf die Funktion Zusammensetzung definiert werden:

(.:) = (.) . (.) 

Es sieht aus wie eine Eule, aber sie sind in der Tat gleichwertig. Somit wird eine andere Art und Weise den Ausdruck schreiben:

relativelyPrime = ((== 1) .) . gcd 

Wenn Sie verstehen wollen, was passiert dann sehen: What does (f .) . g mean in Haskell?

5

wie Sie es kommentiert - wenn Sie wirklich einen Punkt freie Version möchten Sie zuerst uncurry gcd verwenden können gcd in eine Version zu verwandeln, die einen einzelnen Eingang akzeptiert (ein Tupel):

Prelude> :t uncurry gcd 
uncurry gcd :: Integral c => (c, c) -> c 

dann überprüfen Sie mit (== 1) und curry es endlich wieder für die Originalunterschrift: nur das erste Argument

relativeelyPrime = curry ((== 1) . (uncurry gcd)) 

Ihre Version eine Funktion, nur weil gcd produziert nicht funktioniert, wenn und das ist keine rechtliche Eingabe für (== 1), die eine Nummer erwartet.