简体   繁体   English

Haskell“无法推断”错误

[英]Haskell “could not deduce” error

I have the following code: 我有以下代码:

class Coll c e where
    map :: (e1 -> e2) -> c e1 -> c e2
    merge :: (e -> e -> e) -> e -> c e -> e
    sum :: (Num e) => c e -> e
    sum = merge (+) 0

So far so good. 到现在为止还挺好。 But then I have: 但是然后我有:

    sumMap :: (Num e2) => (e1 -> e2) -> c e1 -> e2
    sumMap f c = (merge (+) 0) (map f c)

Compiling gives an error: 编译产生错误:

Could not deduce (Coll c e2) arising from a use a 'merge' from the context (Coll ce) [...] Possible fix: add (Coll c e2) to the context of the type signature for sumMap [...] 无法从上下文(Coll ce)推断出由于使用“合并”而引起的(Coll c e2)[...]可能的解决方法:将(Coll c e2)添加到sumMap [...的类型签名的上下文中]

So I replace sumMap :: (Num e2) => (e1 -> e2) -> c e1 -> e2 with sumMap :: (Num e2, Coll c e2) => (e1 -> e2) -> c e1 -> e2 , but then it gives another error: 所以我将sumMap :: (Num e2) => (e1 -> e2) -> c e1 -> e2 sumMap :: (Num e2, Coll c e2) => (e1 -> e2) -> c e1 -> e2 sumMap :: (Num e2) => (e1 -> e2) -> c e1 -> e2替换为sumMap :: (Num e2, Coll c e2) => (e1 -> e2) -> c e1 -> e2 sumMap :: (Num e2) => (e1 -> e2) -> c e1 -> e2 sumMap :: (Num e2, Coll c e2) => (e1 -> e2) -> c e1 -> e2 ,但随后又出现另一个错误:

Could not deduce (Coll c e0) arising from a use of 'map' from the context (Coll ce) [...] Possible fix: add a type signature that fixes these type variable(s) [...] 无法从上下文(Coll ce)推断出由于使用“ map”而引起的(Coll c e0)[...]可能的解决办法:添加类型签名以修复这些类型变量[...]

I'm confused, so I comment out the definition for sumMap , and run :t (merge (+) 0) . (map (* 2)) 我很困惑,所以我注释掉了sumMap的定义,然后运行:t (merge (+) 0) . (map (* 2)) :t (merge (+) 0) . (map (* 2)) , which gives me [...] :: (Num c, Coll c1 c, Coll c1 e) => c1 c -> c . :t (merge (+) 0) . (map (* 2)) ,这给了我[...] :: (Num c, Coll c1 c, Coll c1 e) => c1 c -> c Ignoring how it mangled my variables' names, Coll c1 e is bizarre; Coll c1 e忽略了变量名称的混乱方式,这很奇怪。 e is not even used in the definition!, so why is it there!? e甚至没有在定义中使用!!为什么在其中!! Anyways, then I run ((merge (+) 0) . (map (* 2))) [1,2,3,4] , which successfully returns 20 . 无论如何,然后我运行((merge (+) 0) . (map (* 2))) [1,2,3,4] ,它成功返回20 What's going on here? 这里发生了什么? Why does this function work only when I don't try to tie it to a name? 为什么仅当我不尝试将其绑定到名称时,此功能才起作用?

Your problems stems from the way you defined your Col class. 您的问题源于您定义Col类的方式。 In particular, the class definition includes both types c and e . 特别地,所述类定义包括两种类型c e This means that you can have different instances for different types of elements—presumably not what you want. 这意味着您可以为不同类型的元素使用不同的实例,大概不是您想要的。 Instead, you want to have a single instance for each possible c that works with any type of element at all. 相反,您想为所有可能与任何类型的元素一起使用的c提供一个实例。

It would be better to write the class as: 最好将类编写为:

class Coll c where
  map :: (e1 -> e2) -> c e1 -> c e2
  merge :: (e -> e -> e) -> e -> c e -> e
  sum :: Num e => c e -> e
  sum = merge (+) 0

Now each individual instance only depends on c , not the type of its elements. 现在,每个单独的实例仅取决于c ,而不取决于其元素的类型。

I suspect that you wrote class Coll ce where because you wanted to ensure that c was a collection of elements. 我怀疑您class Coll ce where编写了class Coll ce where因为您想确保c是元素的集合。 (Like writing C<E> in Java.) However, this is unnecessary in Haskell: a type variable like c can stand in for parameterized types with no other annotation. (就像用Java编写C<E>一样。)但是,这在Haskell中是不必要的:像c这样的类型变量可以代替其他注释而代表参数化类型。 The type system will figure out that c takes a parameter by the way you use it in the signatures for map , merge and so on. 类型系统将确定c通过在mapmerge等的签名中使用参数来采用参数。

Since this is unnecessary, class Coll ce means that the class is based on two different type variables, which don't even have to be related. 由于这是不必要的,因此class Coll ce表示该类基于两个不同的类型变量,它们甚至不必关联。 This means that, to figure out which instance to use, the type system needs to know the specific type for both the collection and its elements, and in your specific case it does not have enough information to do this. 这意味着,要弄清楚要使用的情况下,该类型系统需要知道的收集它的因素,其中包括特定类型,并在特定的情况下,它没有足够的信息来做到这一点。 If you just leave e out of the class definition, it should not be a problem. 如果只将e排除在类定义之外,那应该不是问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM