在查找Polyvariadic函数示例时,我找到了以下资源:StackOverflow: How to create a polyvariadic haskell function?,其中有一个回答片段,如下所示:
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为什么Haskell不能推断在这种情况下我们需要一个Int,考虑到我们在SumRes类型中使用的是Int?
发布于 2015-10-25 19:55:52
实例
instance (...) => SumRes (Int -> r) where大致意思是“这里是如何为任何SumRes (在特定条件下)在Int -> r上定义r”。把它和
instance (...) => SumRes (a -> r) where这意味着“这里是如何为任何SumRes (在特定条件下)在a -> r上定义a,r”。
主要的区别是,第二个实例声明这是相关的实例,无论a,r类型是什么。除了一些(非常棘手和潜在危险的) Haskell扩展,您不能在以后添加更多涉及函数的实例。相反,第一个例子为新的实例留出了空间,例如。
instance (...) => SumRes (Double -> r) where ...
instance (...) => SumRes (Integer -> r) where ...
instance (...) => SumRes (Float -> r) where ...
instance (...) => SumRes (String -> r) where ... -- nonsense, but allowed这与数字文字(如5 )是多态的事实相匹配:它们的类型必须从上下文中推断出来。因为编译器稍后可能会找到一个Double -> r实例,并选择Double作为文本类型,所以编译器不会提交到Int -> r实例,并报告类型错误中的歧义。
请注意,使用一些(安全的) Haskell扩展(如TypeFamilies),可以向编译器“承诺”您的Int -> r是整个程序中唯一声明的扩展。这是这样做的:
instance (..., a ~ Int) => SumRes (a -> r) where ...这将保证处理所有"functional“情况,但要求a实际上是与Int相同的类型。
发布于 2015-10-25 19:14:14
数字文字本身是多态的,而不是Int类型的。
*Main> :t 1
1 :: Num a => a看看当我们得到类型签名时会发生什么:
*Main> :t sumOf 1 2 3
sumOf 1 2 3 :: (Num a, Num a1, SumRes (a -> a1 -> t)) => t注意,该类型根本没有提到Int。类型检查器无法确定如何实际计算和,因为定义的Int实例中没有一个能够在这里应用。
如果您将类型修复为Int,那么您的结果是
*Main> :t sumOf (1 :: Int) (2 :: Int) (3 :: Int)
sumOf (1 :: Int) (2 :: Int) (3 :: Int) :: SumRes t => t
*Main> :t sumOf (1 :: Int) (2 :: Int) (3 :: Int) :: Int
sumOf (1 :: Int) (2 :: Int) (3 :: Int) :: Int注意,SumRes t => t与Int兼容,因为我们有一个SumRes Int实例,但是如果我们没有显式指定Int,那么我们就没有足够通用的实例可以在这里应用,因为没有通用的SumRes t实例。
https://stackoverflow.com/questions/33333614
复制相似问题