Почему эта поливариадная функция требует аннотации типа?

Вот простая поливариадная функция, смоделированная Text.Printf.printf:

{-# LANGUAGE FlexibleInstances #-}

sumOf :: SumType r => r
sumOf = sum' []

class SumType t where
  sum' :: [Integer] -> t

instance SumType (IO a) where
  sum' args = print (sum args) >> return undefined

instance (SumArg a, SumType r) => SumType (a -> r) where
  sum' args = \a -> sum' (toSumArg a : args)

class SumArg a where 
  toSumArg :: a -> Integer

instance SumArg Integer where 
  toSumArg = id

Он прекрасно работает в ghci без каких-либо аннотаций типа:

ghci> sumOf 1 2 3
6

Тем не менее, когда я удаляю SumArg a ограничение...

instance SumType r => SumType (Integer -> r) where
  sum' args = \a -> sum' (toSumArg a : args)

... это не удается:

ghci> sumOf 1 2 3

<interactive>:903:7:
    No instance for (Num a0) arising from the literal `3'
    The type variable `a0' is ambiguous
    Possible fix: add a type signature that fixes these type variable(s)
    Note: there are several potential instances:
      instance Num Double -- Defined in `GHC.Float'
      instance Num Float -- Defined in `GHC.Float'
      instance Integral a => Num (GHC.Real.Ratio a)
      ...plus 14 others
    In the third argument of `sumOf', namely `3'
    In the expression: sumOf 1 2 3
    In an equation for `it': it = sumOf 1 2 3

Как так?

(Если честно, меня больше смущает тот факт, что первая версия не нуждается в аннотациях типов в своих аргументах.)

1 ответ

Решение

Это потому 1 имеет тип Num n => n, Поэтому при поиске подходящего экземпляра для sumOf 1 это не будет соответствовать Integer -> r, Но a -> r всегда совпадает, поэтому он находит совпадение в первом случае, и в конце концов, a по умолчанию Integer, Так что я ожидаю, что это работает, где a ~ Integer сил a становиться Integer:

instance (a ~ Integer, SumType r) => SumType (a -> r) where
  sum' args = \a -> sum' (toSumArg a : args)
Другие вопросы по тегам