为什么这个polyvariadic函数需要类型注释?

时间:2013-10-01 16:44:31

标签: haskell polyvariadic

这是一个简单的多变量函数,以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 个答案:

答案 0 :(得分:4)

这是因为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)