我有t1
类型的t2
和Either String Type
两个值。 Left
- 值用于错误处理。这些值用于返回Either String Type
的函数。
我想要做的是检查t1
和t2
是否Right
- 值并满足p :: Type -> Bool
。如果他们这样做,我想返回Right (the type inside t1)
。如果t1
和t2
都是Right
- 值,但不满足p
,我想返回Left someString
。如果t1
或t2
中的某个值为Left
,我只想传递该值。
我怎样才能以优雅的方式做到这一点?我有一种预感,使用Either作为monad是正确的做法,但我不确定如何去做。
答案 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