2009-05-03 14 views
4

Diese Frage entstand beim Lesen des neuen Kapitels im ausgezeichneten Learn You a Haskell über anwendungsorientierte Funktoren.Woher weiß Haskell, welche Typklasseninstanz Sie meinen?

Die Applicative hat typeclass, als Teil der Definition für die Maybe Beispiel:

pure = Just 

Wenn ich gehen Sie einfach auf GHCi und Import Control.Applicative, und zu tun:

pure (3+) 

I don Hab nichts (macht Sinn). Aber wenn ich es in einem Teil der Ausdruck verwenden:

pure (3+) <*> Just 4 

I Just bekommen 7. Ich denke, es ist auch nicht verwunderlich ist, aber ich bin etwas fehlt Integral darüber, wie typeclasses arbeiten, glaube ich, dass es keine Zweideutigkeit mit dem Anruf an pure hier.

Wenn meine Verwirrung Sinn macht, kann jemand erklären, was im Detail passiert?

Antwort

6

Es ist nur Typ Inferenz. Der Operator (<*>) benötigt beide Argumente, um dieselbe Applicative Instanz zu verwenden. Die rechte Seite ist eine Maybe, also muss die linke Seite auch eine Maybe sein. So ermittelt es, welche Instanz hier verwendet wird. Sie können den Typ eines beliebigen Ausdrucks im Interpreter anzeigen, indem Sie :t expression eingeben. Wenn Sie sich die einzelnen Unterausdrücke ansehen und sich den Typ ansehen, der abgeleitet wurde, erhalten Sie ein besseres Bild von dem, was vor sich geht.

+0

Ah, so tut der Compiler etwas wie "Hmm, der Typ dieses Arguments ist mehrdeutig, also lasst mich den nächsten Argumenttyp überprüfen und zurückkommen"? –

+8

Typ-Inferenz ist ziemlich komplex, aber es ist wissenswert, dass es nicht in einem Schritt geschieht. Der Typ-Inferenzrechner sammelt normalerweise einige Informationen in einem Schritt und zu einem späteren Zeitpunkt einige weitere Informationen. Es ergibt also nicht nur von links nach rechts die richtigen Typen für alles auf einmal.In diesem Fall wird es folgern, dass "rein" vom Typ "(Applicative a1) => a1 (Int -> Int)" ist, wobei "a1" nur eine erfundene Typvariable ist, zu einem späteren Zeitpunkt während der Typinferenz wird schließen, dass 'a1'' Maybe' sein muss, und dann wird es 'Maybe' für' a1' überall ersetzen. –

+0

Danke - das ist sehr hilfreich! –

2

Um die Antwort von newacct ein wenig zu erweitern, wenn der Compiler nicht genügend Informationen zum eigentlichen Typ hat, kann der Compiler (in einigen Fällen) versuchen, einen Standardtyp auszuwählen, der auf die Typabhängigkeiten beschränkt ist Frage. In diesem Fall ist der abgeleitete Typ IO (n -> n) für eine schwierig zu bestimmende Instanz von Num => n. GHCi wertet es dann aus und verwirft den Rückgabewert ohne sichtbaren Effekt.

3

Es lohnt sich auf die Art der Suche der Compiler für pure (3+) folgert:

Prelude Control.Applicative> :t pure (3+) 
pure (3+) :: (Num a, Applicative f) => f (a -> a) 

Der Typ dieser Begriff ist überlastet, und die Entscheidung über die numerische Klasse und der applicative Klasse wird erst später verzögert. Sie können jedoch einen bestimmten Typen mit einer Anmerkung erzwingen, zum Beispiel:

*Showfun Control.Applicative> pure (3+) :: Maybe (Double -> Double) 
Just <function> 

(Dies funktioniert, weil Showfun eine Instanz Deklaration hat, die einen Funktionswert als <function> druckt.)

Es ist nur eine Frage, wann die Der Compiler hat genügend Informationen gesammelt, um eine Entscheidung zu treffen.

+0

Aus Neugier, ist das 'Showfun'-Modul in einem bestehenden Paket, oder ist es nur etwas, das Sie selbst geschrieben haben? Die Implementierung ist einfach genug: 'instance Show (a -> b) wo; show _ = "" ' –

+0

Ich habe selbst Showfun geschrieben, damit ich das Beispiel' pure (3+) 'zum Ausdrucken mit' Just' bekommen konnte. –

+0

ShowFunctions ist jetzt in QuickCheck, glaube ich. – porges

1

Hier ist eine interessante SO thread on type inference. Nicht Haskell-spezifisch, aber viele gute Links und Sachen zum Lesen über Typinferenz in funktionalen Sprachen.

Verwandte Themen