2017-02-05 4 views
4

Ich bin neu in Haskell zu verstehen, und ich habe eine Frage zu dem folgenden Code:den Typen dieser Haskell Funktion

a x (b:bs) = a (b x) bs 
a x b = x [] 

Was die allgemeine Art dieses Musters ist?

Mit :info ein erhalte ich: ([t1] -> t) -> [([t1] -> t) -> [t1] -> t] -> t

Allerdings kann ich warum nicht verstehen. Hat a nur zwei "Eingänge" oder nicht?

+5

Sind Sie sicher, dass das der Typ ist, den Sie für die gesamte Definition erhalten? Es sieht aus wie der Typ, den Sie nur für den zweiten Fall erhalten würden. Wenn Sie die Funktion in GHCi eingeben, müssen Sie die Funktion in einem einzigen "Let" definieren. Wenn Sie zwei "Let's" verwenden, ersetzt der zweite einfach den ersten. – sepp2k

+0

Ok thx Ich werde es versuchen – user1299292

+0

Aah jetzt bekomme ich: ([t1] -> t) -> [([t1] -> t) -> [t1] -> t] -> t – user1299292

Antwort

6

Ich habe nur zwei "Eingänge" oder nicht?

Ja, Sie haben zwei Parameter (technisch eine wegen der Art, wie Currying funktioniert).

mit: info a erhalte ich: ([t1] -> t) -> [([t1] -> t) -> [t1] -> t] -> t

Das bedeutet, der erste Parameter Typ hat [t1] -> t (so ist es eine Funktion, die eine Liste von t1 s nimmt und ein t), der zweite Parameter hat Geben Sie [([t1] -> t) -> [t1] -> t] (eine Liste von Funktionen, die eine Funktion des Typs [t1] -> t und eine Liste von t1 s und produzieren eine t) und das Ergebnis hat Typ t.

Aber ich kann nicht verstehen warum.

Werfen wir einen Blick auf den Code:

a x (b:bs) = 

Der erste Parameter ist nur ein variables Muster, so seine Art ist alles. Der zweite ist ein Listenmuster, also muss es eine Liste sein.

Wenn wir also nummerierte Fragezeichen verwenden Typen bezeichnen wir wissen noch nicht, wir so wissen weit folgendes:

x :: ?1 
b :: ?2 
bs :: [?2] 
a :: ?1 -> [?2] -> ?3 

Jetzt die am Körper aussehen lassen:

a (b x) bs 

b Wird auf x angewendet, so muss b eine Funktion sein, die den Typ x als Parameter verwendet. Das Ergebnis von b x wird als erstes Argument für a verwendet, daher muss der Ergebnistyp b auch dem Typ x entsprechen. So muss ?2?1 -> ?1 sein, und wir erhalten:

x :: ?1 
b :: ?1 -> ?1 
bs :: [?1 -> ?1] 
a :: ?1 -> [?1 -> ?1] -> ?3 

Lassen Sie uns jetzt am zweiten Körper einen Blick (b und bs sind nun nicht mehr in diesem Bereich, technisch gibt es eine neue b, aber es wird nicht verwendet, so wir ll ignorieren):

x [] 

Hier x auf eine leere Liste angewendet wird. Also muss es auch eine Funktion sein und der Parametertyp ist eine Art Liste.Da das Ergebnis von x [] auch das Ergebnis der a, x ist, muss der Ergebnistyp ?3 sein. So bekommen wir ?1 = [?4] -> ?3 und damit:

a :: ([?4] -> ?3) -> [([?4] -> ?3) -> ([?4] -> ?3)] -> ?3 

Seit -> ist rechtsassoziativ, können wir am Ende loszuwerden, die Klammern bekommen dort und erhalten:

a :: ([?4] -> ?3) -> [([?4] -> ?3) -> [?4] -> ?3] -> ?3 

Und jetzt, denn das ist die ganze Art Informationen, die wir haben, alle Fragezeichen, die übrig sind, sind tatsächliche Typvariablen, also können wir sie durch willkürliche Art Variablennamen ersetzen. Wenn wir ?3 = t und ?4 = t1 wählen, erhalten wir die exakte Ausgabe von info (aber natürlich könnten wir ihnen irgend etwas anderes nennen und der Typ wäre immer noch äquivalent).

+0

Vielen Dank für die ausführliche Explantation! Es ist eine gute Idee mit den Questionmarks! – user1299292

1

Wenn Sie nur in der ersten Hälfte der Definition sehen bekommen wir eine schöne Art:

a :: t -> [t -> t] -> t1 
a x (b:bs) = a (b x) bs 

Wir Wert nehmen und eine Reihe von Funktionen aus der Liste, um es anzuwenden. Wir wissen noch nicht, was passiert, wenn wir keine Funktionen mehr haben, weil wir den zweiten Teil noch nicht angeschaut haben.

Lets versuchen eine andere Endung erste vorzustellen:

a :: t -> [t -> t] -> t 
a x [] = x 

Wenn wir getan, was wir unseren endgültigen Wert zurück. Beachten Sie, dass dies unseren unsicheren Rückgabetyp gelöst hat. Da wir nur über eine Liste umgekehrte Funktionsanwendung tun falten wir konnten nur mit umgekehrter Funktion Anwendung über die Liste und Sie erhalten die gleiche Funktion:

a :: t -> [t -> t] -> t 
a = foldl (flip ($)) 

Aber das ist nicht, wie unsere Funktion in Wirklichkeit endet. Es endet mit

a x [] = x [] 

Hier ist, was wir gerade gelernt: x ist eine Funktion, die eine Liste von Somethings und gibt etwas nimmt. Was diese etwas sind, können wir nicht sagen, also nennen wir sie t1 und t2. Wir wissen x ‚s Typ t ist so können wir nur alle Vorkommen von t in unserer ersten Funktion ersetzen mit [t1] -> t2:

a :: ([t1] -> t2) -> [([t1] -> t2) -> ([t1] -> t2)] -> t2 

Und das ist, wie diese Art Signatur passiert ist! Wir wissen auch, dass es entspricht:

a x ls = foldl (flip ($)) x ls $ [] 

was immer noch eine seltsame Funktion ist.