我有一个嵌套的或者与不同的错误类型,看起来像:嵌套Eithers不同的错误类型
Either e1 (Either e2 a)
而且我想,做类似的功能:
Either e1 (Either e2 a) -> Either e2 a
更多一般来说,有没有一种类型符合这种模式?
我有一个嵌套的或者与不同的错误类型,看起来像:嵌套Eithers不同的错误类型
Either e1 (Either e2 a)
而且我想,做类似的功能:
Either e1 (Either e2 a) -> Either e2 a
更多一般来说,有没有一种类型符合这种模式?
你所要求的并不是真的有意义。让我们来看看你的函数的类型:
f :: Either e1 (Either e2 a) -> Either e2 a
假设这个函数是总(因为绝大多数的Haskell函数真的应该是),我们需要生产Either e2 a
类型的值任何输入类型为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
但是等等!这种类型显然不可能满足,因为我们需要一个e2
或一个a
,但我们只有一个e1
。因此,我们不能执行(假设我们不是无限循环或使用error
或undefined
)。我们被卡住了。
不知道你实际上试图做,很难提供一个很好的解决这个问题。我至少可以提供一些可能性,也许其中一个可能与您的用例有关。
一个简单的解决方案是提供一种将e1
值映射到e2
的方法。这样,我们可以将所有错误标准化为e2
。实现这个很容易与either
功能的帮助:
f :: (e1 -> e2) -> Either e1 (Either e2 a) -> Either e2 a
f g = either (Left . g) id
您还可以通过应用映射函数到外Either
的左侧,然后使用一元join
功能合并两个这样做层:
import Data.Bifunctor
f :: (e1 -> e2) -> Either e1 (Either e2 a) -> Either e2 a
f g = join . first g
我们可以处理这将是调整的结果来编码两种可能性的另一种方式。我们可以生成一个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
谢谢,你的文章写得非常好,也帮助我在自己的脑海中回答和澄清这个问题。 为了澄清,e1和e2与错误具有相似的结构,所以我会考虑将e1错误映射到e2错误,所以解决方案1对我的情况非常适用。 – plint
什么你问没有意义除非该功能是部分功能,或者您提供了一些额外的信息。如果外面的价值是“左”呢?那么你没有'e2' *或*'a'类型的值,只有'e1'类型,所以你不能构造'E2a'。 –
我明白你想分组错误(例如在左边),以便得到的类型是'Either(e1 e2)a'。但是现在你想要省略某种类型的错误。 –
所以你想要一个函数,它会带来一个错误并且不会发生错误? – immibis