Подтвердить что ты не робот

Почему ghci дает мне тип для "1 ++ 2" вместо ragequitting?

GHCI даст мне тип для 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]

Но это, очевидно, неправильно. Если я попытаюсь его оценить, вместо того, чтобы просто проверять его, все правильно работает:

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

Что дает?

4b9b3361

Ответ 1

Но это, очевидно, неправильно.

Нет, это абсолютно правильно.

Тип (++) -

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

и тип целочисленных литералов

1 :: Num n => n

Итак, тип [a], который должен иметь аргумент (++), унифицирован с типом Num n => n, который имеет литерал, давая

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

и если у вас есть тип списка с экземпляром Num, это выражение также может быть оценено.

Но по умолчанию для типов списков нет экземпляра Num, поэтому, когда вы пытаетесь его оценить, ghci жалуется, что не находит экземпляр Num для [a].

Например:

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]

Ответ 2

Поскольку кто-то может определять списки, которые будут рассматриваться как числа:

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

Тогда то, что вы набрали, будет работать, поскольку

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

(Не то, чтобы этот экземпляр Num имел бы смысл.)