Haskell,多变量函数和类型推断 [英] Haskell, polyvariadic function and type inference

查看:156
本文介绍了Haskell,多变量函数和类型推断的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在寻找Polyvariadic函数示例时,我发现这个资源:
StackOverflow:如何创建一个polyvariadic haskell函数?,并且有这样的答案片段:

While looking for Polyvariadic function examples, I found this resource: StackOverflow: How to create a polyvariadic haskell function?, and there was an answer snippet like this:

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

然后我们可以使用:

Then we could use:

*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

我尝试过改变它一点点,只是为了好奇,因为我乍一看发现它非常棘手,我进入了这个领域:

I tried out to change it a little bit, just for curiosity, because I found it pretty tricky at first glance, and I got into this:

class SumRes r where
  sumOf :: Int -> r

instance SumRes Int where
  sumOf = id

instance (SumRes r) => SumRes (Int -> r) where
  sumOf x = sumOf . (x +)

我刚刚更改了整数 Int 并转向 instance(Integral a,SumRes r)=> SumRes(a - > r)其中多态性少于 instance(SumRes r)=> SumRes(Int - > r)其中

I just changed Integer to Int and turned instance (Integral a, SumRes r) => SumRes (a -> r) where less polymorphic to instance (SumRes r) => SumRes (Int -> r) where

为了编译它,我必须设置 XFlexibleInstances 标志。当我尝试测试 sumOf 函数时,我遇到了一个问题:

To compile it I had to set XFlexibleInstances flag. When I tryed to test sumOf function I got a problem:

*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...

然后我试过:

Then I tried:

*Main> sumOf (1 :: Int) (1 :: Int) :: Int
2

为什么Haskell在这种情况下推断我们需要 Int ,考虑到我们在<$ $中使用 Int c $ c $> SumRes typeclass?

Why can't Haskell infer that we want an Int in this situation, considering we are using Int within our SumRes typeclass?

推荐答案

实例

instance (...) => SumRes (Int -> r) where

大致意思是这里是如何定义 SumRes Int - > r 上对任何 r (在特定条件下) 。将它与

roughly means "here's how to define SumRes on Int -> r for any r (under certain conditions)". Compare it with

instance (...) => SumRes (a -> r) where

这意味着以下是如何定义 SumRes a - > r 上对任何 a,r )。

which means "here's how to define SumRes on a -> r for any a,r (under certain conditions)".

主要区别在于第二个不同之处在于这是 相关实例,无论类型 a ,r 可能是。除了一些(非常棘手和潜在危险的)Haskell扩展之外,以后不能添加更多的实例来涉及函数。相反,第一个为新的实例留下空间,例如,例如

The main difference is that the second one states that this is the relevant instance whichever the types a,r might be. Barring some (very tricky and potentially dangerous) Haskell extension, one can not add more instances later on involving functions. Instead, the first one leaves room for new instances such as e.g.

instance (...) => SumRes (Double -> r) where ...
instance (...) => SumRes (Integer -> r) where ...
instance (...) => SumRes (Float -> r) where ...
instance (...) => SumRes (String -> r) where ... -- nonsense, but allowed

这是配对的事实上像 5 这样的数字文字是多态的:它们的类型必须从上下文中推断出来。由于稍后编译器可能会发现例如a Double - > r 实例并选择 Double 作为文字类型,编译器不会提交到 Int - >

This is paired with the fact that numeric literals such as 5 are polymorphic: their type must be inferred from the context. Since later on the compiler might find e.g. a Double -> r instance and choose Double as the literal types, the compiler does not commit to the Int -> r instance, and reports the ambiguity in a type error.

请注意,使用一些(安全的)Haskell扩展(例如 TypeFamilies ),可以向编译器承诺你的 Int - > r 是唯一一个将在整个程序中声明的人。这是这样做的:

Note that, using some (safe) Haskell extensions (such as TypeFamilies), it is possible to "promise" to the compiler that your Int -> r is the only one that will be declared in the whole program. This is done like this:

instance (..., a ~ Int) => SumRes (a -> r) where ...

这承诺处理所有功能类型例子,但要求 a 实际上与 Int 类型相同。

This promises to handle all the "functional type" cases, but requires that a is actually the same type as Int.

这篇关于Haskell,多变量函数和类型推断的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆