2010-05-15 29 views
5

Tengo el siguiente código Haskell:problemas con tipos de número de 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 se supone que es un caso de uso de taylor3s. Sin embargo, hay algo mal con la inferencia de tipo de número. Cuando intento compilar, este es el error que consigo:

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 

Alguien me puede ayudar con la comprensión de cuál es el problema?

+3

Siempre proporciono tipos explícitos para las funciones de nivel superior. Hace que el código sea más fácil de leer, y cuando sucede algo así, ayuda a reducir el problema y ayuda al compilador a dar mensajes de error significativos.Sin eso, todo lo que sabes es que hay un error de tipo en alguna parte. –

+1

Sí, normalmente lo haría también, pero no tengo ni idea de los tipos numéricos. ¿Quién sabía que podría haber tantos tipos diferentes de números? – mindeavor

Respuesta

8

Dado que está mezclando operaciones que solo están disponibles en integrales y operaciones que solo están disponibles en fracciones (específicamente usa ^ cuyo segundo operando debe ser integral - use ** si desea que ambos operandos tengan el mismo Tipo flotante), haskell infiere que todos los argumentos y el resultado de taylor3s tienen el tipo Fractional a, Integral a => a. Esto no es un error de tipo, ya que teóricamente podría existir un tipo de este tipo, pero lo más probable es que no sea lo que quieres porque en la práctica ese tipo no existe.

La razón por la que se obtiene un error de tipo de todas formas es que el tipo inferido de taylor_results, en consecuencia, también Fractional a, Integral a => a que es polimórfico y por lo tanto viola la monomorphism restriction.

Si desea declarar explícitamente taylor_results como taylor_results :: Fractional a, Integral a => a o desactivar la restricción monomorphism, todo el asunto sería compilar, pero sea imposible utilizar (sin definir un tipo que realmente crea una instancia integral y fraccional, lo que sería absurdo).

Tenga en cuenta que si se fija este (por ejemplo, mediante la sustitución de ^ con **) el tipo de taylor_results seguirá siendo polimórficos (se infiere como taylor_results :: (Floating a, Enum a) => [a], que en realidad es sensible), por lo que aún se ejecutará en el monomorphism restricción. Por lo tanto, aún debe desactivar la restricción, declarar explícitamente que el tipo de taylor_results es polimórfico o declarar explícitamente que el tipo de taylor_results es un tipo específico que crea una instancia flotante y Enum (por ejemplo, doble). Tenga en cuenta que a menos que haga lo último, taylor_results se volverá a calcular cada vez que lo use (razón por la cual existe la restricción de monomorfismo).

Tenga en cuenta que si se fija este (por ejemplo, mediante la sustitución de ^ con **) el tipo más general de taylor_results será (Floating a, Enum a) => [a], sin embargo, el tipo que te dan (a no ser que se desactiva la restricción monomorphism) será [Double]. Si no desea duplicar, debe declarar explícitamente que taylor_results es de otro tipo (que crea una instancia de Floating y Enum) o que es polimórfico. Tenga en cuenta que si declara que es polimórfico, taylor_results se volverá a calcular cada vez que lo use (razón por la cual existe la restricción de monomorfismo).

+0

+1 Para la respuesta ^/**. Sin embargo, Haskell inferirá taylor_result como taylor_results :: [Double] debido al uso de 0.25 (es decir, un tipo doble) por lo que no habrá restricciones monomórficas – zebrabox

+0

@zebrabox: el tipo de '0.25' es' 0.25 :: (fraccional t) => t', no Doble. Y el tipo inferido de taylor_results es definitivamente '(Flotante a, Enum a) => [a]' después de reemplazar '^' por '**'. De hecho, comprobé esto en ghci. – sepp2k

+1

@zebrabox: Gah, tengo que corregirme. * Sin la restricción de monomorfismo *, el tipo inferido será '(Flotante a, Enum a) => [a]'. Sin embargo, con la restricción habilitada, el tipo se especializará en '[Doble]' sin causar un error debido a las reglas de incumplimiento de Haskell con respecto a los Números. – sepp2k

0

Parece que Haskell está infiriendo el regreso de taylor3s como un tipo Integral, pero entonces el hecho de que las subfunciones f etc se infieren como hacer frente a Fractional tipos viola esa inferencia.

Tal vez al decirle explícitamente a Haskell, el tipo de devolución taylor3s podría ayudar.

Cuestiones relacionadas