Haskell 具有不同错误类型的嵌套EITHER
我有一个包含不同错误类型的嵌套数据库,看起来像:Haskell 具有不同错误类型的嵌套EITHER,haskell,typeclass,either,Haskell,Typeclass,Either,我有一个包含不同错误类型的嵌套数据库,看起来像: Either e1 (Either e2 a) 我想要一个函数,它的功能如下: Either e1 (Either e2 a) -> Either e2 a 更一般地说,是否有与此模式匹配的typeclass?您的函数是不可能的! 你所要求的并没有实际意义。让我们看看函数的类型: f :: Either e1 (Either e2 a) -> Either e2 a f :: (e1 -> e2) -> Either
Either e1 (Either e2 a)
我想要一个函数,它的功能如下:
Either e1 (Either e2 a) -> Either e2 a
更一般地说,是否有与此模式匹配的typeclass?您的函数是不可能的!
你所要求的并没有实际意义。让我们看看函数的类型:
f :: Either e1 (Either e2 a) -> Either e2 a
f :: (e1 -> e2) -> Either e1 (Either e2 a) -> Either e2 a
f g = either (Left . g) id
f :: Either e1 (Either e2 a) -> Either (Either e1 e2) a
f = either (Left . Left) (either (Left . Right) Right)
假设这个函数是total(Haskell中的绝大多数函数都应该是total),我们需要为任何类型的或e1(或e2a)
的输入生成一个类型为或e2a
的值。为了实现这一点,让我们考虑输入的所有“形状”。
结果表明,e1(e2a)
类型的值可以有三种可能的形状:
Left _
Right (Left _)
Right (Right _)
底部的两个形状很容易处理。事实上,我们可以将任何右值映射到自身:
f (Right x) = x
但是,这不处理外部<代码>左侧代码>情况。我们可以从编写模式开始:
f (Left x) = ???
在上面的模式中,我们得到一个值,x
,类型为e1
。我们需要生成类型为的值,要么是e2a
。这意味着我们基本上需要具有以下类型的函数:
g :: e1 -> Either e2 a
但是等等!这种类型显然不可能满足,因为我们需要一个e2
或a
,但我们只有一个e1
。因此,我们无法实现这种情况(假设我们不无限循环或使用error
或undefined
)。我们被卡住了
解决方案1:提供更多信息
如果不知道您实际上在做什么,就很难为这个问题提供一个好的解决方案。我至少可以提供一些可能性,其中一个可能与您的用例相关
一个简单的解决方案是提供一种将e1
值映射到e2
的方法。这样,我们可以将所有错误标准化为e2
。在或功能的帮助下,实现这一点非常容易:
f :: Either e1 (Either e2 a) -> Either e2 a
f :: (e1 -> e2) -> Either e1 (Either e2 a) -> Either e2 a
f g = either (Left . g) id
f :: Either e1 (Either e2 a) -> Either (Either e1 e2) a
f = either (Left . Left) (either (Left . Right) Right)
您也可以通过将映射函数应用到外部或的左侧,然后使用monadicjoin
函数合并两个层来完成此操作:
import Data.Bifunctor
f :: (e1 -> e2) -> Either e1 (Either e2 a) -> Either e2 a
f g = join . first g
解决方案2:更改结果类型
我们可以处理这个问题的另一种方法是调整结果,对这两种可能性进行编码。我们可以生成一个类型为或(e1 e2或)a
的值来保存任何一个可能的错误。使用或
函数编写此代码也相当容易:
f :: Either e1 (Either e2 a) -> Either e2 a
f :: (e1 -> e2) -> Either e1 (Either e2 a) -> Either e2 a
f g = either (Left . g) id
f :: Either e1 (Either e2 a) -> Either (Either e1 e2) a
f = either (Left . Left) (either (Left . Right) Right)
但是,使用模式匹配而不是编写可能更清晰:
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
你的功能是不可能的!
你所要求的并没有实际意义。让我们看看函数的类型:
f :: Either e1 (Either e2 a) -> Either e2 a
f :: (e1 -> e2) -> Either e1 (Either e2 a) -> Either e2 a
f g = either (Left . g) id
f :: Either e1 (Either e2 a) -> Either (Either e1 e2) a
f = either (Left . Left) (either (Left . Right) Right)
假设这个函数是total(Haskell中的绝大多数函数都应该是total),我们需要为任何类型的或e1(或e2a)
的输入生成一个类型为或e2a
的值。为了实现这一点,让我们考虑输入的所有“形状”。
结果表明,e1(e2a)
类型的值可以有三种可能的形状:
Left _
Right (Left _)
Right (Right _)
底部的两个形状很容易处理。事实上,我们可以将任何右值映射到自身:
f (Right x) = x
但是,这不处理外部<代码>左侧代码>情况。我们可以从编写模式开始:
f (Left x) = ???
在上面的模式中,我们得到一个值,x
,类型为e1
。我们需要生成类型为的值,要么是e2a
。这意味着我们基本上需要具有以下类型的函数:
g :: e1 -> Either e2 a
但是等等!这种类型显然不可能满足,因为我们需要一个e2
或a
,但我们只有一个e1
。因此,我们无法实现这种情况(假设我们不无限循环或使用error
或undefined
)。我们被卡住了
解决方案1:提供更多信息
如果不知道您实际上在做什么,就很难为这个问题提供一个好的解决方案。我至少可以提供一些可能性,其中一个可能与您的用例相关
一个简单的解决方案是提供一种将e1
值映射到e2
的方法。这样,我们可以将所有错误标准化为e2
。在或功能的帮助下,实现这一点非常容易:
f :: Either e1 (Either e2 a) -> Either e2 a
f :: (e1 -> e2) -> Either e1 (Either e2 a) -> Either e2 a
f g = either (Left . g) id
f :: Either e1 (Either e2 a) -> Either (Either e1 e2) a
f = either (Left . Left) (either (Left . Right) Right)
您也可以通过将映射函数应用到外部或的左侧,然后使用monadicjoin
函数合并两个层来完成此操作:
import Data.Bifunctor
f :: (e1 -> e2) -> Either e1 (Either e2 a) -> Either e2 a
f g = join . first g
解决方案2:更改结果类型
我们可以处理这个问题的另一种方法是调整结果,对这两种可能性进行编码。我们可以生成一个类型为或(e1 e2或)a
的值来保存任何一个可能的错误。使用或
函数编写此代码也相当容易:
f :: Either e1 (Either e2 a) -> Either e2 a
f :: (e1 -> e2) -> Either e1 (Either e2 a) -> Either e2 a
f g = either (Left . g) id
f :: Either e1 (Either e2 a) -> Either (Either e1 e2) a
f = either (Left . Left) (either (Left . Right) Right)
但是,使用模式匹配而不是编写可能更清晰:
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
除非函数是局部的或者你提供了一些额外的信息,否则你所要求的是没有意义的。如果外部的值是左<代码>怎么办?然后,您没有类型为e2
或a
的值,只有类型为e1
,因此您不能构造或e2 a
。我理解您希望对错误进行分组(例如在左侧),以便生成的类型为或(或e1 e2)a
。但是现在你不知何故想要忽略某种类型的错误。所以你想要一个函数,它接受一个错误并使错误不发生?你所要求的是没有意义的,除非这个函数是部分的或者你提供了一些额外的信息。如果外部的值是左<代码>怎么办?那么您没有类型为e2
或a
的值,只有类型为e1
,因此