我在Haskell中定义了一个将状态和错误处理结合在一起的自定义monad,如下所示:
[user@host h2]$ java -cp h2*.jar org.h2.tools.Shell -user sa -password sa -url jdbc:h2:tcp://localhost/~/mydb
Welcome to H2 Shell 1.4.197 (2018-03-18)
...
sql> CREATE ALIAS IS_PRIME FOR "acme.Function.isPrime";
(Update count: 0, 9 ms)
sql> CALL IS_PRIME(5);
PUBLIC.IS_PRIME(5)
TRUE
(1 row, 31 ms)
代码可以很好地编译,但是在monad中import Control.Applicative
import Control.Monad
data Result a e = Ok a | Error e
newtype StateError s e a = StateError { runStateError :: s -> (Result a e, s) }
instance Functor (StateError s e) where
fmap f m = StateError $
\s -> case runStateError m s of
(Ok x, s1) -> (Ok (f x), s1)
(Error e, s1) -> (Error e, s1)
instance Applicative (StateError s e) where
pure x = StateError $ \s -> (Ok x, s)
a <*> b = ap a b
instance Monad (StateError s e) where
return = pure
m >>= f = StateError $
\s -> case runStateError m s of
(Ok x, s1) -> runStateError (f x) s1
(Error e, s1) -> (Error e, s1)
get = StateError $ \s -> ((Ok s), s)
put s = StateError $ \_ -> ((Ok ()), s)
main = return ()
和fmap
绑定操作符的定义之间似乎存在一些冗余。
如何重新定义绑定运算符以利用函子定义?
如果这不可能,为什么我必须为我的自定义monad定义函子?
如果我不打算在任何地方使用>>=
,这似乎没用。
谢谢
注意:我知道monad转换器存在,也许它们是将现有状态和错误monad合并为一个的正确方法,但是出于学习的原因,我更喜欢这种方法(我对monad的经验很少)。
注意:此问题是我其他问题How to create a monad that combines state and error in Haskell的后续内容。