将Eithers列表转换为包含列表的Either

Dav*_*son 6 haskell

我是Haskell的初学者,我正在研究一些使用Either进行错误处理的Haskell代码.Either的左侧元素表示错误,而右侧元素表示成功结果.代码经常使用Either的Applicative实例,它似乎是为这个用例设计的.

给定一个类型的对象,[Either e r]将它变成类型对象的最优雅的方法是什么Either e [r]?这一点的意思是我们可能有一些来自我们调用的函数的返回值数组,如果这些返回值中的任何一个是错误,我们希望得到该错误并抛弃其他所有内容.如果数组的多个元素有错误,我希望尽可能得到最左边的错误.

通过编写两个函数,我能够在下面的代码中自己解决这个问题,其中一个函数是递归的,但是有更好的方法吗?

type Error = [Char]

myFunc :: [Either Error a] -> Either Error [a]
myFunc = myFunc2 []

myFunc2 :: [a] -> [Either Error a] -> Either Error [a]
myFunc2 r ((Left error):rest) = Left error
myFunc2 r ((Right item):rest) = myFunc2 (r ++ [item]) rest
myFunc2 r [] = Right r

main :: IO()
main = do
  -- This prints: Right [1, 2, 3]
  putStrLn (show (myFunc [Right 1, Right 2, Right 3]))

  -- This prints: Left "division by zero"
  putStrLn (show (myFunc [Right 1, Left "division by zero", Right 3]))
Run Code Online (Sandbox Code Playgroud)

beh*_*uri 17

sequence来自Control.Monad:

sequence :: (Traversable t, Monad m) => t (m a) -> m (t a)
Run Code Online (Sandbox Code Playgroud)

如:

\> import Control.Monad (sequence)

\> sequence [Right 1, Right 2, Right 3]
Right [1,2,3]

\> sequence [Right 1, Left "division by zero", Right 3]
Left "division by zero"
Run Code Online (Sandbox Code Playgroud)

  • @DavidGrayson _default_实现是一样的; [参见源代码中的`sequence = sequenceA`](http://hackage.haskell.org/package/base-4.9.0.0/docs/src/Data.Traversable.html#Traversable).如果你有一个不是monad的applicative,你会使用`sequenceA`. (4认同)
  • @David Grayson 他们做同样的事情;由于历史原因,它们是不同的函数 https://wiki.haskell.org/Functor-Applicative-Monad_Proposal#Redundant_functions (2认同)

mar*_*iop 9

使用sequenceAData.Traversable

  • `sequence`和`sequenceA`对于`Either`是相同的.它们都存在的原因是历史:在Functor-Applicative-Monad Proposal之前`Applicative`不是`Monad`的超类,并且许多功能实现了两次,如`traverse`和`mapM`. (4认同)