Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does ghci give me a type for "1 ++ 2" instead of ragequitting?

Tags:

haskell

GHCI will give me a type for 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]

But this is obviously wrong. If I try and evaluate it, instead of just type check it, things correctly fail:

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

What gives?

like image 975
Dave Avatar asked Feb 23 '13 14:02

Dave


2 Answers

But this is obviously wrong.

No, it's completely correct.

The type of (++) is

(++) :: [a] -> [a] -> [a]

and the type of integer literals is

1 :: Num n => n

So the type [a] that an argument of (++) must have is unified with the type Num n => n that a literal has, giving

1 ++ 2 :: Num [a] => [a]

and if you have a list type with a Num instance, that expression can also be evaluated.

But, by default, there is no Num instance for list types available, so when you try to evaluate it, ghci complains that it finds no Num instance for [a].

For example:

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]
like image 115
Daniel Fischer Avatar answered Nov 20 '22 01:11

Daniel Fischer


Because someone could define lists to be treated as numbers:

instance Num a => Num [a] where
 (+) = zipWith (+)
 (*) = zipWith (*)
 (-) = zipWith (-)
 negate = map negate
 abs = map abs
 signum = map signum
 fromInteger x = [fromInteger x]

Then what you typed would work, since

  1++2 == fromInteger 1++fromInteger 2 == [1]++[2]

(Not that this Num instance would make much sense..)

like image 20
aleator Avatar answered Nov 20 '22 03:11

aleator