关于haskell:你如何匹配类型”Either a b”?

 2022-02-12 

How do you match against the type "Either a b"?

这部分代码的目的是使 size 函数比简单地计算 elems 中的所有元素更有效。我已决定对构成列表的两种类型求和,但我似乎无法创建 size 函数的签名。

1
2
3
instance (Finite a, Finite b) => Finite (Either a b) where
    elems = combineLists [Left x | x <- elems] [Right x | x <-elems]
    size ??? = (size a) + (size b)

从 Prelude 中,我们知道 Either a b = Left a | Right b.

我尝试的第一件事是匹配 Either,但它当然是一个类型,所以这不起作用。接下来,我尝试了 ((Left a) | (Right b)),但也没有继续。似乎没有其他东西与 Either a b.

类型匹配

我能够让 size (Left a) 编译,但由于它缺少 b 组件,我收到错误:

1
2
Ambiguous type variable `b' in the constraint:
  `Finite b' arising from a use of `size' at <interactive>:1:0-12

这在上下文中当然是有道理的,但我真的不知道如何匹配 Either a b.

有人有什么想法吗?


Either a b 类型的东西要么是 Left a 要么是 Right b,所以你有两种情况可以分别处理:

1
2
size (Left x) = size x
size (Right x) = size x

关于不明确类型变量的错误是一个单独的问题。
如果您只是在解释器中输入类似 size (Left 1) 的内容,系统将无法推断出该 Left 1 值的"正确"类型是什么。它可以是 Either Int anything,只要不知道 anything 是什么类型,就无法检查它是否在类 Finite 中(这是 size 所要求的)。

您可以通过指定显式类型签名来避免该问题:

1
size (Left 1 :: Either Int String)

我认为您遇到的核心问题是您想要一个同时代表来自其他两种类型的数据的类型。 Either a b 在给定时间只能是 ab 之一。

同时表示 ab 的简单数据类型是 2 元组。这种东西的类型签名是(a, b),它也是创建一个的表达式,因此模式加工一个:

1
2
3
4
5
> :type (4,5)
(4,5) :: (Num t, Num t1) => (t, t1)
> let f (a, b) = 2*a + b
> f (4,5)
13

您应该考虑使用 2 元组编写第一行,如下所示:

1
 instance (Finite a, Finite b) => Finite (a, b) where

这个 Finite (a, b) 代表什么?成员函数定义是什么?


问题似乎是您需要为 size 提供一个虚拟参数,但您不能在单个 Either a b 中同时传递两种??类型 ab 的虚拟参数。也许您可以使用 elems 来获取每种类型的虚拟对象:

1
size _ = (size . head) (elems :: [a]) + (size . head) (elems :: [b])