Dopo un po 'di armeggiare con un generatore di numeri casuali, sono giunto alla conclusione che la mia comprensione del sistema di tipo Haskell è incompleta, se non del tutto mancante.Come posso migliorare la mia comprensione del sistema Haskell Type?
Ecco un esempio. Sto cercando di generare un flusso di orari degli eventi di Poisson:
import System.Random
import Numeric
bround :: (RealFloat r, Integral b) => b -> r -> r
bround places x = (fromIntegral (round (x * exp)))/exp
where exp = 10.0^places
rndp = (bround 4)
myGen = (mkStdGen 1278267)
infinitePoissonStream :: (RandomGen g, Random r, RealFloat r) => r -> r -> g -> [r]
infinitePoissonStream rate start gen = next:(infinitePoissonStream rate next newGen)
where (rvalue, newGen) = random gen
next = (start - log(rvalue)/rate)
printAll :: (RealFloat r) => [r] -> IO()
printAll [] = return()
printAll (x:xs) = do putStrLn (showFFloat (Just 8) x "")
printAll xs
main = do
printAll (take 10 (infinitePoissonStream 1.0 0.0 myGen))
che mi rimprovera così:
mwe3.hs:23:8:
No instance for (RealFloat r0) arising from a use of `printAll'
The type variable `r0' is ambiguous
Possible fix: add a type signature that fixes these type variable(s)
Note: there are several potential instances:
instance RealFloat Double -- Defined in `GHC.Float'
instance RealFloat Float -- Defined in `GHC.Float'
instance RealFloat Foreign.C.Types.CDouble
-- Defined in `Foreign.C.Types'
...plus one other
In a stmt of a 'do' block:
printAll (take 10 (infinitePoissonStream 1.0 0.0 myGen))
In the expression:
do { printAll (take 10 (infinitePoissonStream 1.0 0.0 myGen)) }
In an equation for `main':
main
= do { printAll (take 10 (infinitePoissonStream 1.0 0.0 myGen)) }
mwe3.hs:23:27:
No instance for (Random r0)
arising from a use of `infinitePoissonStream'
The type variable `r0' is ambiguous
Possible fix: add a type signature that fixes these type variable(s)
Note: there are several potential instances:
instance Random Bool -- Defined in `System.Random'
instance Random Foreign.C.Types.CChar -- Defined in `System.Random'
instance Random Foreign.C.Types.CDouble
-- Defined in `System.Random'
...plus 33 others
In the second argument of `take', namely
`(infinitePoissonStream 1.0 0.0 myGen)'
In the first argument of `printAll', namely
`(take 10 (infinitePoissonStream 1.0 0.0 myGen))'
In a stmt of a 'do' block:
printAll (take 10 (infinitePoissonStream 1.0 0.0 myGen))
mwe3.hs:23:49:
No instance for (Fractional r0) arising from the literal `1.0'
The type variable `r0' is ambiguous
Possible fix: add a type signature that fixes these type variable(s)
Note: there are several potential instances:
instance Fractional Double -- Defined in `GHC.Float'
instance Fractional Float -- Defined in `GHC.Float'
instance Integral a => Fractional (GHC.Real.Ratio a)
-- Defined in `GHC.Real'
...plus two others
In the first argument of `infinitePoissonStream', namely `1.0'
In the second argument of `take', namely
`(infinitePoissonStream 1.0 0.0 myGen)'
In the first argument of `printAll', namely
`(take 10 (infinitePoissonStream 1.0 0.0 myGen))'
Dopo aver frugato, ho "fisso" cambiando l'ultima riga:
printAll (take 10 (infinitePoissonStream 1.0 0.0 myGen) :: [Double])
Ora, ho voluto usare l'aritmetica limitata precisione, così ho cambiato la linea "Avanti" per questo:
next = rndp (start - log(rvalue)/rate)
e ora non riesce così:
mwe3.hs:15:29:
Could not deduce (r ~ Double)
from the context (RandomGen g, Random r, RealFloat r)
bound by the type signature for
infinitePoissonStream :: (RandomGen g, Random r, RealFloat r) =>
r -> r -> g -> [r]
at mwe3.hs:12:26-83
`r' is a rigid type variable bound by
the type signature for
infinitePoissonStream :: (RandomGen g, Random r, RealFloat r) =>
r -> r -> g -> [r]
at mwe3.hs:12:26
In the first argument of `(-)', namely `start'
In the first argument of `rndp', namely
`(start - log (rvalue)/rate)'
In the expression: rndp (start - log (rvalue)/rate)
Così sto cominciando a giungere alla conclusione che io davvero non so quello che sto facendo. Quindi:
- Qualcuno può spiegare cosa mi manca qui?
- Eventuali puntatori a capitolo e verso in cui potrei avere una possibilità di comprendere i principi di base?
Grazie (+1). Un altro, virtuale, +1 per il consiglio stilistico, e le mie scuse a tutti coloro i cui occhi sono stati feriti dal mio stile di codifica. Dalla tua risposta deduco, forse erroneamente, che potrebbe essere meglio abbandonare del tutto l'uso della classe RealFloat e andare direttamente a 'Double' al posto di' r'. È giusto? –
@ Brent.Longborough Per lo più ho incollato il codice nel mio editor e ho evidenziato dove potresti liberarti di parentesi che non stavano facendo nulla. Anche il newline-at-do-block è solo uno dei miei animaletti, ma il tuo stile non era particolarmente offensivo. Per quanto riguarda i tipi, direi che solo tu puoi sapere se hai bisogno della flessibilità di 'RealFloat'. Se prevedi di usarlo per tipi diversi da "Double", mantienilo così com'è. Se la userai solo con 'Double', cambia semplicemente la firma per usare esplicitamente' Double'. – bheklilr