使特定函数成为Haskell中Monad的一个实例

时间:2016-03-24 19:31:10

标签: function haskell functional-programming monads

我正在关注菲利普·瓦德勒关于Monads的论文(The essence of functional programming),但我没有使用unitMbindM这样的函数,而是试图制作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的实例?”

1 个答案:

答案 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"