haskell - MultiParamTypeClasses - 为什么这个类型变量不明确?

标签 haskell types typeclass language-extension

假设我定义了 multi-parameter type class :

{-# LANGUAGE MultiParamTypeClasses, AllowAmbiguousTypes, FlexibleContexts, FlexibleInstances #-}

class Table a b c where
  decrement :: a -> a
  evalutate :: a -> b -> c

然后我定义一个使用 decrement 的函数,为简单起见:
d = decrement

当我尝试在 ghci 中加载它时(版本 8.6.3):
• Could not deduce (Table a b0 c0)
    arising from a use of ‘decrement’
  from the context: Table a b c
    bound by the type signature for:
               d :: forall a b c. Table a b c => a -> a
    at Thing.hs:13:1-28
  The type variables ‘b0’, ‘c0’ are ambiguous
  Relevant bindings include d :: a -> a (bound at Thing.hs:14:1)
  These potential instance exist:
    instance Table (DummyTable a b) a b

这让我很困惑,因为 d 的类型正是 decrement 的类型,在类声明中表示。

我想到了以下解决方法:
data Table a b = Table (a -> b) ((Table a b) -> (Table a b))

但这似乎在符号上不方便,而且我也只是想知道为什么我首先会收到此错误消息。

最佳答案

问题是,由于 decrement只需要 a类型,无法确定哪些类型 bc应该是,即使在调用函数的时候(从而将多态性解决为特定类型) - 因此,GHC 将无法决定使用哪个实例。

例如:假设您有两个 Table 实例:Table Int String Bool , 和表 Int Bool Float ;你调用你的函数d在应该将一个 Int 映射到另一个 Int 的上下文中 - 问题是,它匹配两个实例! ( a 两者都是 Int )。

注意,如果你让你的函数等于 evalutate :

d = evalutate

然后编译器接受它。这是因为,由于 evalutate取决于三个类型参数 a、b 和 c,调用站点的上下文将允许明确的实例解析 - 只需在调用它的位置检查 a、b 和 c 的类型。

当然,对于单参数类型类来说,这通常不是问题——只有一种类型需要解决;当我们处理多个参数时,事情变得复杂......

一种常见的解决方案是使用 functional dependencies - 制作 bc取决于 a :

 class Table a b c | a -> b c where
  decrement :: a -> a
  evalutate :: a -> b -> c

这告诉编译器,对于给定类型的每个 Table 实例 a ,只有一个实例(bc 将由 a 唯一确定);所以它会知道不会有任何歧义并接受您的d = decrement高兴地。

关于haskell - MultiParamTypeClasses - 为什么这个类型变量不明确?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56487391/

相关文章:

haskell - 重叠实例可以,但仍然失败

typeclass - Rust:使用特征/类型类来实现通用数字函数

Haskell Int -> Word64 转换

function - 根据类型为泛型函数提供不同的函数体

Haskell 到 F# - 在 f# 中声明递归类型

go - 为 switch 中的类型实现逻辑或

haskell - 格式化长模式匹配

python-3.x - 如何在Python中传递给类类型的类方法参数?

Java初学者 boolean 问题

scala - 如何将类型类模式与子类型相结合?