从一个函数返回两种不同的类型

2 haskell types function return-value

如何从单个函数返回多个类型的值?

我想做的事情如下:

take x y  | x == []   = "error : empty list"
          | x == y    = True
          | otherwise = False
Run Code Online (Sandbox Code Playgroud)

我有必要的语言背景.

Tik*_*vis 9

有一个类型构造函数Either,可以让您创建一个可以是两种类型之一的类型.它通常用于处理错误,就像在您的示例中一样.你会像这样使用它:

take x y | x == []   = Left "error : empty list"
         | x == y    = Right True
         | otherwise = Right False
Run Code Online (Sandbox Code Playgroud)

那样的类型take会是这样的Eq a => [a] -> [a] -> Either String Bool.Either用于错误处理的约定是Left表示错误并Right表示正常返回类型.

如果您有Either类型,则可以对其进行模式匹配以查看它包含的值:

case take x y of
  Left errorMessage -> ... -- handle error here
  Right result      -> ... -- do what you normally would
Run Code Online (Sandbox Code Playgroud)


Jed*_*dai 9

您的问题有几种解决方案,具体取决于您的意图:您是否希望在您的类型中制作您的功能可能失败的清单(在这种情况下,您希望返回失败的原因,如果有的话,这可能是不必要的这里只有一种失败模式)或者你估计在这个函数中得到一个空列表根本不应该发生,所以想要立即失败并抛出异常?

因此,如果您想明确表示类型失败的可能性,可以使用Maybe,只是在没有解释的情况下指出失败(最终在您的文档中):

take :: (Eq a) => [a] -> [a] -> Maybe Bool
take [] _ = Nothing
take x y  = x == y
Run Code Online (Sandbox Code Playgroud)

或者要么注册失败的原因(注意,一般来说,或者是"从一个函数返回两种类型"的答案,尽管你的代码更具体):

take :: (Eq a) => [a] -> [a] -> Either String Bool
take [] _ = Left "Empty list"
take x y  = Right $ x == y
Run Code Online (Sandbox Code Playgroud)

最后,您可以发出信号,表示此故障完全异常且无法在本地处理:

take :: (Eq a) => [a] -> [a] -> Bool
take [] _ = error "Empty list"
take x y  = x == y
Run Code Online (Sandbox Code Playgroud)

请注意,使用这种最后一种方式,调用站点不必立即处理失败,实际上它不能,因为异常只能在IO monad中捕获.使用前两种方式,必须修改调用站点以处理失败(并且可以)的情况,如果仅对其自身调用"错误".

有一个最终解决方案允许调用代码选择您想要的失败模式(使用失败包http://hackage.haskell.org/package/failure):

take :: (Failure String m, Eq a) => [a] -> [a] -> m Bool
take [] _ = failure "Empty list"
take x y  = return $ x == y
Run Code Online (Sandbox Code Playgroud)

这可以模仿Maybe和Either解决方案,或者你可以使用take作为IO Bool,如果它失败将抛出异常.它甚至可以在[Bool]上下文中工作(如果失败则返回空列表,这有时很有用).