2010-05-15 17 views
5

Ho il seguente codice Haskell:problemi con i tipi di numero di Haskell

fac n = product [1..n] 

taylor3s w0 f f' f'' t h = w1 : taylor3s w1 f f' f'' (t+h) h 
    where hp i = h^i/fac i 
     w1 = w0 + (hp 1) * f t w0 + (hp 2) * f' t w0 + (hp 3) * f'' t w0 

taylor_results = take 4 $ taylor3s 1 f f' f'' 1 0.25 
    where f t x = t^4 - 4*x/t 
     f' t x = 4*t^3 - 4*(f t x)/t + 4*x/t^2 
     f'' t x = 12*t^2 - 4*(f' t x)/t + 8*(f t x)/t^2 - 8*x/t^3 

taylor_results si suppone che sia un caso d'uso di taylor3s. Tuttavia, c'è qualcosa di sbagliato nel tipo di inferenza del numero. Quando provo a compilare, questo è l'errore che ottengo:

practice.hs:93:26: 
    Ambiguous type variable `a' in the constraints: 
     `Integral a' 
     arising from a use of `taylor3s' at practice.hs:93:26-51 
     `Fractional a' arising from a use of `f' at practice.hs:93:37 
    Possible cause: the monomorphism restriction applied to the following: 
     taylor_results :: [a] (bound at practice.hs:93:0) 
    Probable fix: give these definition(s) an explicit type signature 
        or use -XNoMonomorphismRestriction 

Qualcuno mi può aiutare con la comprensione qual è il problema?

+3

Fornisco sempre tipi espliciti per le funzioni di primo livello. Rende il codice più facile da leggere e, quando succede qualcosa del genere, aiuta a restringere il problema e aiuta il compilatore a dare messaggi di errore significativi.Senza che tutto ciò che sai è che c'è un errore di tipo lì da qualche parte. –

+1

sì, di solito lo farei anch'io, ma sono abbastanza all'oscuro sui tipi numerici. Chi sapeva che potevano esserci così tanti tipi diversi di numeri? – mindeavor

risposta

8

Dal momento che stai operazioni che sono disponibili solo su integrali e operazioni che sono disponibili solo su fractionals (nello specifico si utilizza ^ di cui il secondo operando deve essere integrale miscelazione - utilizzare ** se si intende per entrambi gli operandi abbiano lo stesso Floating type), haskell deduce che tutti gli argomenti e il risultato di taylor3s hanno il tipo Fractional a, Integral a => a. Questo non è un errore di tipo, dal momento che teoricamente potrebbe esistere un tipo, ma probabilmente non è quello che vuoi perché in pratica un tale tipo non esiste.

La ragione per cui si ottiene un errore di tipo comunque è che il tipo derivato di taylor_results è quindi anche Fractional a, Integral a => a che è polimorfica e viola la monomorphism restriction così.

Se volete dichiarare esplicitamente taylor_results come taylor_results :: Fractional a, Integral a => a o disattivare la restrizione monomorfismo, il tutto sarebbe compilare, ma essere impossibile da usare (senza definire un tipo che in realtà un'istanza integrale e frazionata, il che sarebbe una sciocchezza).

nota che se si corregge questo (per esempio sostituendo ^ con **) il tipo di taylor_results sarà ancora polimorfico (sarà dedotto come taylor_results :: (Floating a, Enum a) => [a], che è in realtà sensibile), così ancora correre nella monomorfismo restrizione. Quindi è ancora necessario disattivare la restrizione, dichiarare esplicitamente il tipo di taylor_results in modo polimorfico o dichiarare esplicitamente che il tipo di taylor_results sia un tipo specifico che crea un'istanza di Floating ed Enum (ad esempio Double). Si noti che, a meno che non si esegua quest'ultima, taylor_results verrà ricalcolata ogni volta che viene utilizzata (motivo per cui esiste la limitazione del monomorfismo).

Si noti che se si fissa questa (ad esempio sostituendo ^ con **) il tipo più generale di taylor_results sarà (Floating a, Enum a) => [a], tuttavia il tipo che si ottiene (a meno che non si disattiva la restrizione monomorfismo) sarà [Double]. Se non vuoi duplicati, devi dichiarare esplicitamente che taylor_results è di un altro tipo (che istanzia Floating ed Enum) o che è polimorfico. Notare che se si dichiara polimorfo, taylor_results verrà ricalcolato ogni volta che lo si utilizza (motivo per cui esiste la limitazione del monomorfismo).

+0

+1 per la risposta ^/**. Comunque Haskell dedurrà taylor_result come taylor_results :: [Double] a causa dell'uso di 0.25 (cioè un tipo Double) quindi non ci saranno restrizioni monomorfiche – zebrabox

+0

@zebrabox: Il tipo di '0.25' è' 0.25 :: (Frazionale t) => t', non Double. E il tipo inferito di taylor_results è sicuramente '(Floating a, Enum a) => [a]' dopo aver sostituito '^' con '**'. Ho effettivamente controllato questo in ghci. – sepp2k

+1

@zebrabox: Gah, devo correggermi. * Senza la restrizione del monomorfismo * il tipo inferito sarà '(Floating a, Enum a) => [a]'. Tuttavia, con la restrizione abilitata, il tipo sarà specializzato in '[Double]' senza causare un errore a causa delle regole di haskell relative a Numbers. – sepp2k

0

Sembra che Haskell è inferire il ritorno di taylor3s ad essere un tipo Integral, ma poi il fatto che le sottofunzioni f ecc sono desunti da trattare con Fractional tipi viola che l'inferenza.

Forse dicendo esplicitamente a Haskell il tipo di ritorno taylor3s potrebbe essere d'aiuto.

Problemi correlati