2013-04-04 4 views
5

Voglio fare una lista di numeri ogni 0.1 da -150 a 150.Perché non è possibile mappare una funzione che si moltiplica per Fractional in una lista di Nums?

Per fare questo, ho creato una lista, e poi ha cercato di mappare una lambda moltiplicazione frazionale su di esso, in questo modo:

let indices = [-1500,-1499..1500] 
let grid = map (\x -> 0.1 *x) indices 

Questo rende ghci sputare fuori un errore.

D'altra parte, entrambi questi funzionano bene:

let a = 0.1*2 

e

let grid = map (\x -> 2 *x) indices 

cosa sta succedendo qui? Perché la moltiplicazione di un numero di un frazionale fallisce solo se applicata a un elenco con mappa?

EDIT: L'errore che ottengo è:

No instance for (Fractional Integer) 
    arising from the literal `0.1' 
Possible fix: add an instance declaration for (Fractional Integer) 
In the first argument of `(*)', namely `0.1' 
In the expression: 0.1 * x 
In the first argument of `map', namely `(\ x -> 0.1 * x)' 
+1

Qual è l'errore che stai ottenendo? –

+2

Ah, la restrizione del monomorfismo, colpisce di nuovo. – Carl

+0

@SamiN: ho aggiunto l'errore alla domanda. – Dan

risposta

10

Hai scoperto la "limitante limitazione del monomorfismo". Fondamentalmente GHC dedurrà il tipo di indices ad essere un monotipo come [Integer] invece di Num a => a. È possibile fornire un'annotazione come indices :: [Float] o rielaborare le definizioni per evitare la restrizione.

Per esempio (non un suggerimento), se si effettua una funzione indices: let indices a = [-1500, -1499..1500], il tipo derivato è ora (Enum t, Num t) => a -> [t]. Il parametro a non è utilizzato ma sconfigge la restrizione. Quindi puoi fare map f (indices whatever). Vedi molte più informazioni in Haskell Wiki riguardo allo Monomorphism Restriction.

+0

Puoi specificare dove esattamente uno metterebbe l'annotazione 'indices :: [Float]' in questo codice? Tutti gli esempi di haskell che ho trovato online usano solo l'inferenza di tipo. – Dan

+0

Sì, è possibile scrivere l'annotazione del tipo separatamente dalla dichiarazione come 'let indices :: [Float]; indices = [-1500, -1499..1500] 'oppure puoi annotare il lato destro della definizione' let indices = [-1500, -1499..1500] :: [Float] '. – kputnam

-1

Il seguente codice ha funzionato per me

let indices = [-1500,-1499..1500] 

let grid = map (\x -> x /10) indices 

che non gli piace il 0,1

Per una spiegazione dettagliata vedere la sezione " Guasto monomorfico "su questo link

+0

Questo sputa ancora lo stesso errore per me. – Dan

+0

sto usando The Glorious Glasgow Haskell Compilation System, versione 7.0.3 e il file conteneva appena queste righe e funzionava –

+0

@Dan Questo codice 'map (\ x -> x/10) [-1500, -1499..1500 ] "funziona su http://tryhaskell.org/ –

8

Questo è l'impostazione predefinita.

La variabile indices, piuttosto che essere polimorfico negli Num typeclass come ci si potrebbe aspettare, è inadempiente per intero, a quel punto non si può moltiplicare per 0.1, dal momento che 0.1 risolverà a qualche tipo frazionario.

Si potrebbe forzare gli indici di essere polimorfico con una firma di tipo esplicito:

let indices :: (Enum a, Num a) => [a]; indices = [-1500,-1499..1500] 

anche se in pratica non lo fai spesso vogliono liste esplicitamente polimorfici in quel modo.

V'è una pagina di restrizione monomorfismo sulla wiki Haskell anche se non è particolarmente succinta: http://www.haskell.org/haskellwiki/Monomorphism_restriction

+0

Non dimenticare che avrai bisogno anche di 'Enum a' nella firma. – kputnam

+3

Si noti che se si mettono insieme queste definizioni in un file, anche senza le firme dei tipi va tutto bene. La restrizione del monomorfismo si applica ancora, ma con l'intero contesto disponibile GHC può scegliere un tipo * corretto * monomorfico piuttosto che "[Intero]'. Il modo in cui funziona l'inadempienza non è così stupido, è solo che l'inserimento dei legami in ghci uno alla volta costringe GHC a "lavorare cieco". – Ben

+0

@ Ben: Penso che non sia abbastanza preciso. Non puoi digitare 'let indices' e' let grid' al livello più alto di un file. Sono permessi legami nello stile monadico. E due "lascia" separati in stile monadico non sono reciprocamente ricorsivi. Se fosse * o * plain 'indices =' e 'grid =' al livello più alto, o se fosse un singolo 'let' con due clausole come in' let indices = ...; grid = .... 'quindi assolutamente, si ottiene un punto eccellente - il defaulting viene applicato su interi gruppi di definizioni. – drquicksilver

1
let grid = map (\x -> 0.1 * (fromInteger x)) indices 

- griglia [-150,0, -149,9, -149,8, -149,70000000000002, -149,6, - 149,5 ...]

Problemi correlati