嵌套的Eithers具有不同的错误类型

时间:2017-07-31 01:08:02

标签: haskell typeclass either

我有一个嵌套的不同错误类型,如下所示:

Either e1 (Either e2 a)

我想要一个像以下一样的功能:

Either e1 (Either e2 a) -> Either e2 a

更一般地说,是否存在匹配此模式的类型类?

1 个答案:

答案 0 :(得分:5)

你的功能是不可能的!

你所要求的并不是真正有意义的。让我们看一下你的函数类型:

f :: Either e1 (Either e2 a) -> Either e2 a

假设这个函数是完全的(因为Haskell中的绝大多数函数应该是真的),我们需要为类型为{{em>任何输入的输入生成Either e2 a类型的值。 1}}。为了尝试实现这一点,让我们考虑一下输入的所有“形状”。

事实证明,Either e1 (Either e2 a)类型的值可以有三种可能的形状:

Either e1 (Either e2 a)

底部两个形状易于处理。实际上,我们可以将任何Left _ Right (Left _) Right (Right _) 值映射到自身:

Right

但是,这不会处理外部f (Right x) = x 情况。我们可以从编写模式开始:

Left

在上面的模式中,我们得到一个值为f (Left x) = ??? 的值为x的值e1。我们需要生成Either e2 a类型的值。这意味着我们基本上需要一个具有以下类型的函数:

g :: e1 -> Either e2 a

但是等等!这种类型显然无法满足,因为我们需要e2a,但我们所拥有的只是e1。因此,我们无法实现该情况(假设我们不会无限循环或使用errorundefined)。我们被困住了。

解决方案1:提供更多信息

在不知道你真正想要做什么的情况下,很难为这个问题提供一个好的解决方案。我至少可以提供一些可能性,其中一个可能与您的用例相关。

一个简单的解决方案是提供一种将e1值映射到e2的方法。这样,我们可以将所有错误标准化为e2。借助either函数

,实现此功能非常简单
f :: (e1 -> e2) -> Either e1 (Either e2 a) -> Either e2 a
f g = either (Left . g) id

您也可以通过将映射函数应用到外部Either的左侧,然后使用monadic join函数合并两个图层来执行此操作:

import Data.Bifunctor

f :: (e1 -> e2) -> Either e1 (Either e2 a) -> Either e2 a
f g = join . first g

解决方案2:更改结果类型

我们可以处理这个问题的另一种方法是调整结果以编码两种可能性。我们可以生成Either (Either e1 e2) a类型的值来保存可能的错误。使用either函数编写它也很容易:

f :: Either e1 (Either e2 a) -> Either (Either e1 e2) a
f = either (Left . Left) (either (Left . Right) Right)

然而,使用模式匹配而不是either写的更清晰:

f :: Either e1 (Either e2 a) -> Either (Either e1 e2) a
f (Left x) = Left (Left x)
f (Right (Left x)) = Left (Right x)
f (Right (Right x)) = Right x