Tofu 实例中的模式匹配 [LYAH 示例]

Pattern matching in instances of Tofu [LYAH example]

我在玩 LYAH 的奇怪豆腐示例。我通过从 Frank 构造函数中删除记录字段来稍微简化它,所以就是这样:

class Tofu t where
    tofu :: j a -> t a j

data Frank a m = Frank (m a) deriving (Show)

instance Tofu Frank where
    tofu x = Frank x

它正在运行并且相当清晰。但是现在我想让 a 类型的值被 tofu 函数修改。所以我开始在实例声明中扩展 x 的值:

instance Tofu Frank where
    tofu (m y) = Frank (m y)

结果我得到:

tofu.hs:13:15: Parse error in pattern: m

好的,接下来我尝试在实例声明中进行实际的模式匹配:

instance Tofu Frank where
    tofu (Just y) = Frank (Just y)

结果我得到:

tofu.hs:16:15:
    Couldn't match type `j' with `Maybe'
      `j' is a rigid type variable bound by
          the type signature for tofu :: j a -> Frank a j at tofu.hs:16:9
    Expected type: j a
      Actual type: Maybe a
    In the pattern: Just y
    In an equation for `tofu': tofu (Just y) = Frank (Just y)
    In the instance declaration for `Tofu Frank'

所以,问题是:如何在豆腐的实例声明中使用 a 类型的值?是否可以在不修改 Tofu 的情况下使失败的示例工作 class?

TL;DR:你不能。

假设 t 满足 Tofu t。函数类型状态

tofu :: j a -> t a j

这实际上意味着

tofu :: forall j a. j a -> t a j   -- t is chosen by the class instance

因此,调用者可以选择 ja 是什么。调用者可以传递 [Int]Maybe CharEither String Bool(此处为 j ~ Either Stringa ~ Bool)。函数 tofu 不能假设任何特定情况,并且必须仅使用 "general" 操作来完成它的工作。

how to work with value of type a in instance declaration of tofu

可能没有 a 值。例如

data T a = K Int

因为我们可以将豆腐实例化为

tofu :: T a -> t a T

我们可以像 tofu (K 6 :: T Bool) 那样调用它,即使周围没有 Bool

类似的论点适用于

data U a = U (a -> Int)

这里 U Bool 包含一个需要 Bool 的函数,而不是提供或 "containing" 它,松散地说。