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

OK, niente di troppo insolito qui. Solo le regole di default del tipo GHCi, immagino ...GHCi ignora la firma del tipo

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

Che stregoneria è questa ?? Sei punto di riferimento ignorando la dichiarazione del mio tipo ?! O_O

C'è un modo in cui posso convincere GHCi a fare ciò che intendevo realmente?

+1

selvaggio indovinare: il temuto restrizione monomorfismo. – Jubobs

+0

@Jubobs Anche questa sarebbe la mia ipotesi - tranne che una firma di tipo esplicito non lo disabilita? – MathematicalOrchid

+1

Stai usando una vecchia versione di GHC? Sono su 7.8.3 e ottengo la segnatura del tipo che dovresti * generalmente * aspettare ('Mostra a => a -> IO()'), anche senza usare un'espressione di firma. Ottenere '() -> IO()' sembra un vero problema con GHC. – MasterMastic

risposta

16

Possiamo fare quanto segue, con la limitazione monomorfismo on:

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

Questo non è lo stesso di let myprint = putStrLn . show :: Show x => x -> IO(). Nel primo caso abbiamo un'associazione con una firma di tipo, in quest'ultimo caso abbiamo un binding let con un'annotazione di tipo sul lato destro. Il monomorfismo verifica le firme dei tipi di livello superiore, ma non le annotazioni locali.

+1

Raccomando sempre il flag ': set + m', che consente di eseguire l'input su più righe in GHCi. È molto utile in casi come questo, anche se desidero che GHCi abbia un rientro intelligente con input multi-linea come IPython (il progetto che Jupyter sta lavorando per risolvere questo problema, però) – bheklilr

21

Aggiunta annotazione di tipo a un espressione come in

e :: type 

rende il controllo compilatore che ha e che type, così come l'uso che type per guidare variabili di tipo istanziazione e selezione esempio. Tuttavia, se lo type è polimorfico, può essere istanziato in seguito. Si consideri ad es.

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

Sopra, a vengono istanziati a String, nonostante la mia annotazione. Inoltre,

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

farà a creare un'istanza di Int in seguito. L'annotazione sopra id non fornisce alcuna informazione a GHC: sa già che id ha quel tipo. Potremmo rimuoverlo senza modificare il tipo di controllo. Cioè, le espressioni id e id :: a->a non sono solo equivalenti dinamicamente, ma anche staticamente tali.

Allo stesso modo, le espressioni

putStrLn . show 

e

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

sono staticamente equivalenti: stiamo solo annotare il codice con il tipo di GHC può dedurre. In altre parole, non forniamo alcuna informazione a GHC che non conosce già.

Dopo aver controllato l'annotazione, GHC può quindi istanziare ulteriormente x. La restrizione del monomorfismo lo fa nel tuo esempio. Per evitare questo, utilizzare un'annotazione per il vincolante si stanno introducendo, non per l'espressione :

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