2017-04-06 5 views
3

Ich versuche, das folgende Stück Code zu verstehen:Warum funktioniert diese Funktion, obwohl das Argument fehlt?

import Data.Char (ord) 

encodeInteger :: String -> Integer 
encodeInteger = read . concatMap ch 
    where ch c = show (ord c) 

Aber ich sehe nicht, wie das funktionieren kann, wenn encodeInteger als eine Funktion definiert, die eine Zeichenfolge annimmt, aber in der zweiten Zeile, das Funktion wird ohne dieses String-Argument implementiert.

Auch, concatMap (nach Hoogle), nimmt eine Funktion und eine Liste, aber nur die Funktion ch wird zur Verfügung gestellt.

Warum funktioniert dieser Code noch? Ist das Argument irgendwie magisch passiert? Hat es etwas mit Curry zu tun?

edit: Und warum es nicht, es so zu ändern, arbeiten:

encodeInteger :: String -> Integer 
encodeInteger a = read . concatMap ch a 
    where ch c = show (ord c) 
+1

Eine Funktion "a -> b -> c" in Haskell bedeutet eine Funktion "a -> (b -> c)", d.h. wenn sie auf ein "a" angewendet wird, erzeugt sie ein "b -> c". 'f a b' ist ebenfalls nur '(f a) b'. Da 'concatMap' (vereinfacht)' (a -> [b]) -> [a] -> [b] 'ist, ist' concatMap ch' eine a-Funktion '[a] -> [b]'. – Ryan

+0

Hallo, danke, das macht irgendwie alles Sinn. Aber sollte ich nicht in der Lage sein zu tun, was ich unter Bearbeiten hinzugefügt habe? – user66875

+1

@ user66875 Sie müssen die gesamte Zusammensetzung auf das Argument anwenden. Im Moment erwartet man, dass 'concatMap ch a 'eine Funktion ist (das zweite Argument von' .'). Verwenden Sie 'lesen. concatMap ch $ a' – Lazersmoke

Antwort

4

Grundsätzlich definieren eine Funktion

f = g 

ist die gleiche wie die Definition der Funktion

f x = g x 

In Ihrem speziellen Fall können Sie

verwenden
encodeInteger a = (read . concatMap ch) a 

, um Ihre Funktion zu definieren. Die Klammern benötigt werden, sonst wird es analysiert als

encodeInteger a = (read) . (concatMap ch a) 

und concatMap ch a ist keine Funktion und nicht zusammengesetzt werden kann. Allenfalls könnte man

encodeInteger a = read (concatMap ch a) 
-- or 
encodeInteger a = read $ concatMap ch a 

über "Warum concatMap ch nur ein Argument?" Schreiben. Dies ist eine teilweise Anwendung, die in Haskell sehr häufig ist. Wenn Sie

f x y z = x+y+z 

haben, können Sie f mit weniger Argumente nennen, und als Ergebnis eine Funktion der übrigen Argumente erhalten. Zum Beispiel ist f 1 2 die Funktion, die z nimmt und 1+2+z zurückgibt.

Konkret, dank Currying gibt es keine Funktion, die zwei oder mehr Argumente benötigt. Jede Funktion benötigt immer nur ein Argument. Wenn Sie eine Funktion wie

foo :: Int -> Bool -> String 

haben dann nimmt foo ein Argument, eine Int. Es gibt eine Funktion zurück, die eine Bool nimmt und schließlich eine String zurückgibt. Sie können dies durch

foo :: Int -> (Bool -> String) 

Auf jeden Fall schriftlich visualisieren, wenn Sie und teilweise Anwendung nachschlagen currying, werden Sie viele Beispiele finden.

3
encodeInteger :: String -> Integer 
encodeInteger = read.concatMap (\char -> show $ ord char) 

Die encodeInteger auf der linken Seite (LHS) von "=" ist ein Name; es bezieht sich auf die Funktion auf der rechten Seite (RHS) von "=". Beide haben den Funktionstyp: String -> Integer. Beide nehmen eine Liste von Zeichen und erzeugen eine Ganzzahl.Mit Haskell können wir eine solche Funktionsgleichheit ohne Angabe von formalen Argumenten ausdrücken (ein Stil, der als point-free bekannt ist).

Schauen wir uns jetzt die RHS an. Der Operator (.) Setzt zwei Funktionen zusammen. Die composed-Funktion nimmt einen String als Eingabe von concatMap und erzeugt eine Ganzzahl, die aus read als Ausgabe der zusammengesetzten Funktion kommt.

concatMap selbst braucht 2 Eingänge, aber wir müssen die zweite für die Composed-Funktion weglassen, die eine Zeichenfolge als Eingabe benötigt. Dies erreichen wir, indem wir teilweise nur das erste Argument concatMap anwenden.

Verwandte Themen