22

letterali numerici hanno un tipo polimorfico:Perché i valori polimorfici non vengono dedotti in Haskell?

*Main> :t 3 
3 :: (Num t) => t 

Ma se mi legano una variabile a tale letterale, il polimorfismo si perde:

x = 3 
... 
*Main> :t x 
x :: Integer 

Se io definisco una funzione, d'altra parte, è naturalmente polimorfa:

f x = 3 
... 
*Main> :t f 
f :: (Num t1) => t -> t1 

potrei fornire una firma tipo per garantire la x rimane polimorfa:

x :: Num a => a 
x = 3 
... 
*Main> :t x 
x :: (Num a) => a 

Ma perché è necessario? Perché il tipo polimorfico non è desunto?

+0

Farebbe qualche differenza? (Davvero non lo so, anche se non sospetto) – delnan

+3

Fa la differenza; Voglio che il tipo rimanga il più generale possibile. –

+0

Vieni di nuovo? Non importa se 'x' è' Integer' o 'Num a => a', puoi passarlo a qualsiasi funzione che si aspetta un' Num'. Le funzioni devono essere generiche, i valori no. – delnan

risposta

24

È il monomorphism restriction che dice che tutti i valori, che sono definiti senza parametri e non hanno un'annotazione di tipo esplicita, dovrebbero avere un tipo monomorfico. Questa limitazione può essere disabilitata in ghc e ghci usando -XNoMonomorphismRestriction.

La ragione per la restrizione è che senza questa restrizione long_calculation 42 sarebbero stati valutati due volte, mentre la maggior parte delle persone probabilmente aspetta/vuole che sia valutata solo una volta:

longCalculation :: Num a => a -> a 
longCalculation = ... 

x = longCalculation 42 

main = print $ x + x 
+0

Ah sì, la temuta limitazione del monomorfismo ... ne ho sentito parlare, ma non ho mai visto cosa fosse esattamente. Grazie! –

+0

Se aggiungo firme di tipo esplicite a questo, verrebbe comunque valutato due volte, con l'estensione di limitazione senza monomorfismo? –

+0

@JustinL Se ha un tipo polimorfico, verrà valutato due volte. Se ha un tipo monomorfico, non lo farà. La restrizione del monomorfismo riguarda solo se otterrà un tipo monomorfico o polimorfico senza annotazioni. Se aggiungi annotazioni, la limitazione del monomorfismo non fa differenza. – sepp2k

20

Per espandere sulla risposta di sepp2k un po ': se si tenta di compilare il seguente (o caricarlo in GHCi), si ottiene un errore:

import Data.List (sort) 
f = head . sort 

questa è una violazione della restrizione monomorfismo perché abbiamo un vincolo di classe (introdotto da sort), ma non ex Argomenti impliciti: siamo (in qualche modo misteriosamente) a dire che abbiamo un nel vincolo Ord a.

Il vostro esempio (let x = 3) ha una variabile di tipo simile ambiguo, ma non dà lo stesso errore, perché è salvato da Haskell's "defaulting" rules:

Any monomorphic type variables that remain when type inference for an entire module is complete, are considered ambiguous, and are resolved to particular types using the defaulting rules (Section 4.3.4).

Vedi this answer per ulteriori informazioni sulle inadempienti regole-il il punto importante è che funzionano solo per determinate classi numeriche, quindi x = 3 va bene mentre non lo è lo standard f = sort.

Come nota a margine: se si preferisce che x = 3 finiscono per essere un Int invece di un Integer, e y = 3.0 essere un Rational invece di un Double, è possibile utilizzare una "dichiarazione di default" per ignorare l'impostazione predefinita inadempiente regole :

default (Int, Rational) 
+0

+1, eccellente supplemento alla risposta di sepp2k –

+1

Quando metto 'f = head. sort' in un file e provo a caricarlo, ottengo un errore, ma quando digito' let f = head. sort' in GHCi non ottengo alcun errore, e il l'associazione risultante ha questo tipo: 'f :: [()] ->()'. Che succede? –

+2

@pelotom: È a causa delle [regole predefinite estese] di GHCi (http://www.haskell.org/ GHC/docs/6.12.2/html/users_guide/interattivo-evaluation.html # extended-default-regole). –

Problemi correlati