我正在关注菲利普·瓦德勒关于Monads的论文(The essence of functional programming),但我没有使用unitM
或bindM
这样的函数,而是试图制作Monad M
Haskell的一个实例Monad
。我为第一个和第二个变体做了这个。但是现在我正在尝试为第三个变体做这个,我们必须创建一个Monad,它也保持错误信息的位置
本文描述了以下功能:(E
是第二种变体中的Monad错误)
type Position = Integer
type P a = Position -> E a
unitP a = \p -> unitE a
errorP s = \p -> errorE (showpos p ++ ": " ++ s)
m `bindP` k = \p -> m p `bindE` (\x -> k x p)
showP m = showE (m 0)
resetP :: Position -> P x -> P x
resetP q m = \p -> m q
现在,我的问题是:“如何让P a = Position -> E a
成为Monad
的实例?”
答案 0 :(得分:1)
这是一个自定义monad实现:
-- Otherwise you can't do the Applicative instance.
import Control.Applicative
-- Simple function
foo :: String -> String
foo x = do
x ++ "!!!"
-- Helper for printing Monads
print2 :: (Show a) => MyBox a -> IO()
print2 (MyBox x) = print x
-- Custom type declaration
data MyBox a = MyBox a
-- MyBox functor
instance Functor MyBox where
fmap f (MyBox x) = MyBox (f x)
-- MyBox Applicative
instance Applicative MyBox where
pure = MyBox
(MyBox f) <*> x = f <$> x
-- MyBox Monad
instance Monad MyBox where
return x = MyBox x
MyBox x >>= f = f x
-- (MyBox as a functor) Use a function with a wrapped value
result1 = foo <$> (MyBox "Brian")
-- (MyBox as an Applicative) Use a wrapped function with a wrapped value
result2 = (MyBox foo) <*> (MyBox "Erich")
-- (MyBox as a Monad) Use a wrapped value with a lambda (it can be chainable)
myLambda1 = (\ x -> MyBox (x ++ " aaa"))
myLambda2 = (\ x -> MyBox (x ++ " bbb"))
myLambda3 = (\ x -> MyBox (x ++ " ccc"))
result3 = (MyBox "Rick")
>>= myLambda1
>>= myLambda2
>>= myLambda3
-- Another Monad syntax
result4 = do
x <- MyBox "A"
y <- MyBox "B"
z <- MyBox "C"
MyBox (x ++ y ++ z)
main = do
print2(result1) -- "Brian!!!"
print2(result2) -- "Erich!!!"
print2(result3) -- "Rick aaa bbb ccc"
print2(result4) -- "ABC"