在Haskell中使用'Either'

时间:2011-06-09 09:27:19

标签: haskell monads either

我有t1类型的t2Either String Type两个值。 Left - 值用于错误处理。这些值用于返回Either String Type的函数。

我想要做的是检查t1t2是否Right - 值并满足p :: Type -> Bool。如果他们这样做,我想返回Right (the type inside t1)。如果t1t2都是Right - 值,但不满足p,我想返回Left someString。如果t1t2中的某个值为Left,我只想传递该值。

我怎样才能以优雅的方式做到这一点?我有一种预感,使用Either作为monad是正确的做法,但我不确定如何去做。

4 个答案:

答案 0 :(得分:10)

为什么是monads?

test p (Right t1) (Right t2) | p t1 && p t2 = Right t1
                             | otherwise = Left "nope"
test _ (Left t1) _ = Left t1
test _ _ (Left t2) = Left t2

答案 1 :(得分:5)

如果您确实想要使用Monad,它会看起来像这样,但Monad的{​​{1}}实例最近被更改,因此这实际上不会起作用最近的GHC:

Either

答案 2 :(得分:3)

您可以创建自己的Error数据类型并使其成为Monad的实例。

data Computation a = Error String | Result a


instance Monad Computation where
    (Result x)  >>= k   =  k x
  e@(Error a)   >>= k   =  e

然后使用method described by Ganesh Sittampalam。 (您还需要添加MonadPlus Computation实例。

更新表示完整性,如下所示:

import Control.Monad

data Computation a = Error String | Result a



instance Monad Computation where
  return a = Result a
  (Result x)  >>= k   =  k x
  (Error a)   >>= k   =  Error a

instance MonadPlus Computation where
  mzero              = Error "Always fail"
  mplus (Error a) r  = r
  mplus l         _  = l


check :: (Int -> Bool) -> Computation Int  
check p =   do v1 <- Result 4
               v2 <- Result 2
               guard (p v1 && p v2) `mplus` Error "someString"
               return v1

答案 3 :(得分:1)

如果你真的想要,你可以将monadic动作与Left值的传播分开:

import Control.Monad
import Control.Applicative
import Control.Monad.Instances

这产生了简单的monadic动作:

foo :: Type -> Type -> Either String Type
foo t1 t2 | p t1 && p t2 = Right t1
          | otherwise    = Left somestring

您可以使用

应用于monadic参数以获得所需的功能
fooM :: Either String Type -> Either String Type -> Either String Type
fooM t1 t2 = join (foo <$> t1 <*> t2)

或等效

fooM t1 t2 = do
    a <- t1
    b <- t2
    foo a b