Почему эта поливариадная функция требует аннотации типа?
Вот простая поливариадная функция, смоделированная 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)