2013-04-16 11 views
9

A pagina 321 di Real World HaskellPerché è possibile omettere la funzione di costruzione quando si fa riferimento a tipi di numeri avvolti di nuovo tipo?

Ci sono questi codici,

...

{-# LANGUAGE GeneralizedNewtypeDeriving #-} 
newtype AInt = A { unA::Int } 
    deriving (Show, Eq, Num) 

instance Monoid AInt where 
    mempty = 0 

La mia confusione è per questo che è

mempty = 0 

ma non

mempty = A 0 

?


Ho anche notato che sia

ghci> 0 :: AInt 

e

ghci> A 0 :: AInt 

mi danno la stessa risposta

A { unA = 0 } 

Qualcuno per favore mi dica qual è la differenza tra la tesi Due?

risposta

13

Il trucco qui è con l'estensione GeneralizedNewtypeDeriving. In particolare, questo ci consente di derivare qualsiasi classe per un valore di newtype a condizione che il tipo sottostante sia un'istanza. Tutto ciò che fa è copiare l'istanza dal vecchio tipo al nuovo tipo.

In questo caso particolare, AInt deriva Num. Ciò significa che AInt è un'istanza di Num che utilizza lo stesso codice di Int (con tutto ciò che è racchiuso nei costruttori A a seconda dei casi). Ciò include la funzione fromInteger di.

La funzione fromInteger è definita in termini di Int s' fromInteger, cercando qualcosa di simile:

fromInteger i = A (fromInteger i) 

Dal 0 è polimorfico - ha il tipo 0 :: Num a => a --è è una costante valida per qualsiasi digitare Num. Grazie al newtype derivante, questo include AInt, utilizzando la funzione fromInteger sopra. Ciò significa che non vi è alcuna differenza tra 0 :: AInt e A 0 :: AInt.

+4

Quindi è la stessa ragione per cui possiamo fare sia '1 :: Float' che' 1 :: Int'? – Znatz

+2

@Znatz: Sì. Dato che 'AInt' è in' Num', può usare i letterali come 'Float',' Int' e una tonnellata di altri tipi. –

+0

: Grazie mille! – Znatz

12

I valori letterali numerici come 0 sono sovraccarichi e hanno il tipo 0 :: Num a => a, il che significa che possono essere di qualsiasi tipo per cui esiste un'istanza Num, a seconda del contesto. Ciò avviene tramite la funzione fromInteger nella classe di tipo Num, pertanto quando si digita 0 viene trattato come se fosse stato scritto fromInteger 0.

Utilizzando GeneralizedNewtypeDeriving, GHC ha (in modo efficace) scritto un'istanza Num per la classe cercando qualcosa di simile:

instance Num AInt where 
    fromInteger n = A (fromInteger n) 
    ... 

Quindi, quando si scrive 0 :: AInt, questo si espande a fromInteger 0 :: AInt che è (dal definizione sopra) uguale a A (fromInteger 0), che è lo stesso come se avessi scritto A 0.

GeneralizedNewtypeDeriving in realtà non scrive una nuova prospettiva. Esegue semplicemente i cast necessari per utilizzare quello esistente.

+0

In realtà scrive una nuova istanza, mi è stato detto. Il difficile è che le istanze della superclasse potrebbero non essere derivate da GND, il che invalida i puntatori delle istanze della superclasse. Cioè, potresti, credo, scrivere 'instance Eq Foo dove ...; derivando l'esempio Ord Foo'. Per evitare di incorrere in problemi in questi casi, mi viene detto che GHC costruisce nuovi dizionari, ma riutilizza i membri. – dfeuer

Problemi correlati