2015-03-22 7 views
20
Prelude> let myprint = putStrLn . show 
Prelude> :t myprint 
myprint ::() -> IO() 

OK, nichts zu ungewöhnlich hier. Nur GHCi Typ Standardregeln, ich denke, ...GHCi ignoriert Typ Unterschrift

Prelude> let myprint = (putStrLn . show) :: Show x => x -> IO() 
Prelude> :t myprint 
myprint ::() -> IO() 

Welche Zauberei ist das? Sie sind auf den Punkt Ignorieren meine Typ-Deklaration ?! O_O

Gibt es eine Möglichkeit, GHCi davon zu überzeugen, das zu tun, was ich eigentlich wollte?

+1

wilde Vermutung: die gefürchtete Monomorphie Einschränkung. – Jubobs

+0

@Jubobs Das wäre meine Vermutung - außer dass eine explizite Art Signatur das nicht deaktiviert? – MathematicalOrchid

+1

Verwenden Sie eine alte Version von GHC? Ich bin auf 7.8.3 und erhalte die Typensignatur, die man * allgemein * erwarten würde ('Zeige a => a -> IO()'), auch ohne einen Signaturausdruck zu verwenden. Getting '() -> IO()' scheint ein echtes Problem mit GHC. – MasterMastic

Antwort

16

Wir können Folgendes tun, mit Monomorphie Einschränkung:

>let myprint :: Show x => x -> IO(); myprint = putStrLn . show 
>:t myprint 
myprint :: Show x => x -> IO() 

Dies ist nicht das gleiche wie let myprint = putStrLn . show :: Show x => x -> IO(). Im ersten Fall haben wir eine Bindung mit einer Typ-Signatur, im letzteren Fall haben wir eine let Bindung mit einer Typ-Annotation auf der rechten Seite. Beim Monomorphismus werden Typensignaturen der obersten Ebene überprüft, nicht jedoch lokale Annotationen.

+1

Ich empfehle immer die ': set + m' Flagge, die Sie mehrzeilige Eingabe in GHCi lässt tun. Es ist wirklich praktisch für Fälle wie diese, obwohl ich wünsche GHCi intelligente Vertiefung mit Multi-Line-Eingang wie IPython (Projekt Jupyter über die Festsetzung dieses arbeitet, obwohl) hatte – bheklilr

21

Hinzufügen einer Anmerkung zu einem Typ Ausdruck wie in

e :: type 

macht den Compiler Überprüfen, dass e dass type hat, sowie die Verwendung dass type Typvariablen Instantiierung und Instanz-Auswahl zu fahren. Jedoch, wenn die type polymorph ist, kann sie später noch instanziiert werden. Betrachten wir z.B.

(id :: a -> a) "hello" 

Oben, a wird String trotz meiner Anmerkung instanziert werden. Des Weiteren wird

foo :: Int -> Int 
foo = (id :: a -> a) 

machen a später zu Int instanziiert werden. Die obige id Annotation gibt keine Informationen an GHC: Sie weiß bereits, dass id diesen Typ hat. Wir könnten es entfernen, ohne die Typprüfung überhaupt zu beeinflussen. Das heißt, die Ausdrücke id und sind nicht nur dynamisch äquivalent, sondern auch statisch.

ähnlich sind die Ausdrücke

putStrLn . show 

und

(putStrLn . show) :: Show x => x -> IO() 

sind statisch gleichwertig: Wir Kommentierung nur den Code mit dem Typ GHC ableiten kann. Mit anderen Worten, wir stellen GHC keine Informationen zur Verfügung, die es nicht bereits kennt.

Nachdem die Annotation typisiert ist, kann GHC die Instanz x weiter instanziieren. Die Monomorphie-Einschränkung macht das in Ihrem Beispiel. Um das zu verhindern, eine Anmerkung für die Bindung verwenden Sie einführen, nicht für den Ausdruck:

myprint :: Show x => x -> IO() 
myprint = (putStrLn . show)