haskell - online - ¿Por qué ghci me da un tipo para "1++ 2" en lugar de hacer rabia?
haskell pdf (2)
GHCI me dará un tipo para 1 ++ 2
:
$ ghci
GHCi, version 7.4.2: http://www.haskell.org/ghc/ :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Prelude> :t 1 ++ 2
1 ++ 2 :: Num [a] => [a]
Pero esto está obviamente mal. Si trato de evaluarlo, en lugar de escribirlo, las cosas fallan correctamente:
Prelude> 1 ++ 2
<interactive>:3:1:
No instance for (Num [a0])
arising from the literal `1''
Possible fix: add an instance declaration for (Num [a0])
In the first argument of `(++)'', namely `1''
In the expression: 1 ++ 2
In an equation for `it'': it = 1 ++ 2
¿Lo que da?
Pero esto está obviamente mal.
No, es completamente correcto.
El tipo de (++)
es
(++) :: [a] -> [a] -> [a]
y el tipo de literales enteros es
1 :: Num n => n
Entonces, el tipo [a]
que debe tener un argumento de (++)
se unifica con el tipo Num n => n
que tiene un literal, dando
1 ++ 2 :: Num [a] => [a]
y si tiene un tipo de lista con una instancia de Num
, esa expresión también se puede evaluar.
Pero, de forma predeterminada, no hay ninguna instancia de Num
para los tipos de lista disponibles, por lo que cuando intenta evaluarla, Ghci se queja de que no encuentra ninguna instancia de Num
para [a]
.
Por ejemplo:
Prelude> instance Num a => Num [a] where fromInteger n = Data.List.genericReplicate n 1
<interactive>:2:10: Warning:
No explicit method or default declaration for `+''
In the instance declaration for `Num [a]''
<interactive>:2:10: Warning:
No explicit method or default declaration for `*''
In the instance declaration for `Num [a]''
<interactive>:2:10: Warning:
No explicit method or default declaration for `abs''
In the instance declaration for `Num [a]''
<interactive>:2:10: Warning:
No explicit method or default declaration for `signum''
In the instance declaration for `Num [a]''
Prelude> 1 ++ 2 :: [Int]
[1,1,1]
Porque alguien podría definir listas para ser tratadas como números:
instance Num a => Num [a] where
(+) = zipWith (+)
(*) = zipWith (*)
(-) = zipWith (-)
negate = map negate
abs = map abs
signum = map signum
fromInteger x = [fromInteger x]
Entonces lo que escribiste funcionaría, ya que
1++2 == fromInteger 1++fromInteger 2 == [1]++[2]
(No es que este caso Num
tenga mucho sentido ...)