【发布时间】:2016-01-24 20:03:59
【问题描述】:
在寻找多变量函数示例时,我发现了这个资源: StackOverflow: How to create a polyvariadic haskell function?,有这样一个回答sn-p:
class SumRes r where
sumOf :: Integer -> r
instance SumRes Integer where
sumOf = id
instance (Integral a, SumRes r) => SumRes (a -> r) where
sumOf x = sumOf . (x +) . toInteger
那么我们可以使用:
*Main> sumOf 1 :: Integer
1
*Main> sumOf 1 4 7 10 :: Integer
22
*Main> sumOf 1 4 7 10 0 0 :: Integer
22
*Main> sumOf 1 4 7 10 2 5 8 22 :: Integer
59
出于好奇,我尝试对其进行了一些更改,因为乍一看我觉得它很棘手,所以我进入了这个:
class SumRes r where
sumOf :: Int -> r
instance SumRes Int where
sumOf = id
instance (SumRes r) => SumRes (Int -> r) where
sumOf x = sumOf . (x +)
我刚刚将Integer 更改为Int 并将instance (Integral a, SumRes r) => SumRes (a -> r) where 的多态性降低为instance (SumRes r) => SumRes (Int -> r) where
要编译它,我必须设置XFlexibleInstances 标志。当我尝试测试sumOf 函数时,我遇到了问题:
*Main> sumOf 1 :: Int
1
*Main> sumOf 1 1 :: Int
<interactive>:9:9
No instance for (Num a0) arising from the literal `1'
The type variable `a0' is ambiguous...
然后我尝试了:
*Main> sumOf (1 :: Int) (1 :: Int) :: Int
2
考虑到我们在SumRes 类型类中使用Int,为什么Haskell 不能在这种情况下推断出我们想要Int?
【问题讨论】:
-
看起来默认(假设
1表示Int1)在ghci中的实例解析后启动。没错。您可以为Integer添加一组单独的 step-case 实例而不是Int,然后您就会有一个真正的歧义。 -
您可能想阅读this question, and my answer to it 以了解另一个方向的一些解释,以及一个可以用来处理此处错误类型推断的有用技巧:使用
instance a ~ Int => SumRes (a -> r)而不是instance SumRes (Int -> r)。 -
为了澄清关于默认的部分,
Int不是通常默认的类型,但Integer是。因此,原始代码通过将所有文字默认为Integer来工作。 -
我的评论有点天真,因为即使在更改的代码中放置
Integer而不是Int也不足以修复它。 (刚刚发布的duplicate question 让我意识到了这一点。)
标签: haskell recursion typeclass polyvariadic