Joh*_*ner 2 haskell compiler-errors function
我有以下代码:
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
Run Code Online (Sandbox Code Playgroud)
到现在为止还挺好.但后来我有:
sumMap :: (Num e2) => (e1 -> e2) -> c e1 -> e2
sumMap f c = (merge (+) 0) (map f c)
Run Code Online (Sandbox Code Playgroud)
编译会出错:
无法推断(Coll c e2)因使用来自上下文的"合并"(Coll ce)[...]可能的修复:将(Coll c e2)添加到sumMap的类型签名的上下文中[...] ]
所以我替换sumMap :: (Num e2) => (e1 -> e2) -> c e1 -> e2为sumMap :: (Num e2, Coll c e2) => (e1 -> e2) -> c e1 -> e2,但后来又给出了另一个错误:
无法推断(Coll c e0)从上下文中使用'map'(Coll ce)[...]可能的修复:添加修复这些类型变量的类型签名[...]
我很困惑,所以我评论出来的定义sumMap,然后运行:t (merge (+) 0) . (map (* 2)),这给了我[...] :: (Num c, Coll c1 c, Coll c1 e) => c1 c -> c.忽略它如何破坏我变量的名称,Coll c1 e是奇怪的; e甚至没有在定义中使用!,为什么它在那里!?无论如何,然后我跑((merge (+) 0) . (map (* 2))) [1,2,3,4],成功返回20.这里发生了什么?为什么只有当我不试图将它与名称联系起来时,此功能才有效?
您的问题源于您定义Col课程的方式.特别是,类定义包括两种类型c 和 e.这意味着您可以为不同类型的元素提供不同的实例 - 可能不是您想要的.相反,您希望每种可能的单个实例都c适用于任何类型的元素.
将类编写为:
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
Run Code Online (Sandbox Code Playgroud)
现在每个实例仅依赖c于其元素的类型.
我怀疑你写的class Coll c e where是因为你想确保这c是一个元素的集合.(就像C<E>在Java中编写一样.)但是,在Haskell中这是不必要的:类型变量就像c可以代表没有其他注释的参数化类型一样.类型系统将c根据您在签名中使用它的方式来确定参数map,merge依此类推.
由于这是不必要的,class Coll c e意味着该类基于两个不同的类型变量,甚至不必相关.这意味着,要弄清楚要使用的情况下,该类型系统需要知道集合双方的具体类型和它的元素,并且在特定情况下,它没有足够的信息来做到这一点.如果你e不在课堂定义之外,那应该不是问题.
| 归档时间: |
|
| 查看次数: |
168 次 |
| 最近记录: |