简体   繁体   English

如何在 GHC 7.10 或更新版本中创建 monad

[英]How to create a monad in GHC 7.10 or newer

In the book "Haskell programming from first principles" it is said that:在“Haskell programming from first principles”一书中说:

If you are using GHC 7.10 or newer, you'll see an Applicative constraint in the definition of Monad, as it should be:如果您使用的是 GHC 7.10 或更新版本,您将在 Monad 的定义中看到一个 Applicative 约束,因为它应该是:

 class Applicative m => Monad m where (>>=):: ma -> (a -> mb) -> mb (>>):: ma -> mb -> mb return:: a -> ma

I have created the following applicative functor.我创建了以下应用函子。

data WhoCares a = ItDoesnt | Matter a | WhatThisIsCalled deriving (Eq, Show)

instance Functor WhoCares where
    fmap _ ItDoesnt = ItDoesnt
    fmap _ WhatThisIsCalled = WhatThisIsCalled
    fmap f (Matter a) = Matter (f a)

instance Applicative WhoCares where
    pure = Matter
    Matter f <*> Matter a = Matter (f a)

main = do

    -- fmap id == id
    let funcx = fmap id "Hi Julie"
    let funcy = id "Hi Julie"
    print(funcx)
    print(funcy)
    print(funcx == funcy)

    -- fmap (f . g) == fmap f . fmap g
    let funcx' = fmap ((+1) . (*2)) [1..5]
    let funcy' = fmap (+1) . fmap (*2) $ [1..5]
    print(funcx')
    print(funcy')
    print(funcx' == funcy')

    -- pure id <*> v = v
    print(pure id <*> (Matter 10))

    -- pure (.) <*> u <*> v <*> w = u <*> (v <*> w)
    let appx = pure (.) <*> (Matter (+1)) <*> (Matter (*2)) <*> (Matter 10)
    let appy = (Matter (+1)) <*> ((Matter (*2)) <*> (Matter 10))
    print(appx)
    print(appy)
    print(appx == appy)

    -- pure f <*> pure x = pure (f x)
    let appx' = pure (+1) <*> pure 1 :: WhoCares Int
    let appy' = pure ((+1) 1) :: WhoCares Int
    print(appx')
    print(appy')
    print(appx' == appy')

    -- u <*> pure y = pure ($ y) <*> u
    let appx'' = Matter (+2) <*> pure 2
    let appy'' = pure ($ 2) <*> Matter (+ 2)
    print(appx'')
    print(appy'')
    print(appx'' == appy'')

Due to lack of examples, I am not understanding how to implement >>= and >> .由于缺少示例,我不了解如何实施>>=>> The code I came up with so far is:到目前为止我想出的代码是:

instance Monad (WhoCares a) where
    (>>=) :: Matter a -> (a -> Matter b) -> Matter b
    (>>) :: Matter a -> Matter b -> Matter b
    return :: a -> Matter a
    return = pure

So, that I can do stuff like:所以,我可以做类似的事情:

half x = if even x
            then Matter (x `div` 2)
            else ItDoesnt

incVal :: (Ord a, Num a) => a -> WhoCares a
incVal x
    | x + 1 <= 10 = return (x + 1)
    | otherwise = ItDoesnt

decVal :: (Ord a, Num a) => a -> WhoCares a
decVal x
    | x - 1 >= 0 = return (x - 1)
    | otherwise = ItDoesnt

main = do
    print (Matter 7 >>= incVal >>= incVal >>= incVal)
    print (Matter 7 >>= incVal >>= incVal >>= incVal >>= incVal)
    print (Matter 7 >>= incVal >>= incVal >>= incVal >>= incVal >>= decVal >>= decVal)
    print (Matter 2 >>= decVal >>= decVal >>= decVal)
    print(Matter 20 >>= half >>= half)

With Output:使用 Output:

10
ItDoesnt
ItDoesnt
ItDoesnt
5

Please help.请帮忙。

How to implement a monad instance for a given data type is in general not answerable without concrete information for how you want that instance to behave – there can be multiple valid instances for a single type.如果没有有关您希望该实例如何行为的具体信息,通常无法回答如何为给定数据类型实现 monad 实例——单个类型可以有多个有效实例。

For this example though, I see only one way: make it behave like the equivalent form不过,对于这个例子,我只看到一种方法:让它表现得像等价形式

data ItIsCalled = ItDoesn't | WhatThisIsCalled
newtype WhoCares a = WhoCares { caresWho :: Either ItIsCalled a }

So I suggest looking up the Monad (Either c) instance and basing yours on that.所以我建议查找Monad (Either c)实例并以此为基础。 The difference is that the Left case corresponds to two different constructors of your type, so you need a clause for each of them.不同之处在于Left案例对应于您的类型的两个不同构造函数,因此您需要为每个构造函数创建一个子句。

OP Here.在这里。 I have removed WhatThisIsCalled .我已经删除了WhatThisIsCalled

Now the solution looks like:现在解决方案看起来像:

data WhoCares a = ItDoesnt | Matter a deriving (Eq, Show)

instance Functor WhoCares where
    fmap _ ItDoesnt = ItDoesnt
    fmap f (Matter a) = Matter (f a)

instance Applicative WhoCares where
    pure = Matter
    Matter f <*> Matter a = Matter (f a)
    ItDoesnt <*> _ = ItDoesnt
    _ <*> ItDoesnt = ItDoesnt

instance Monad WhoCares where
    return x = Matter x
    (Matter x) >>= k = k x
    ItDoesnt >>= _ = ItDoesnt

half x = if even x
            then Matter (x `div` 2)
            else ItDoesnt

incVal :: (Ord a, Num a) => a -> WhoCares a
incVal x
    | x + 1 <= 10 = return (x + 1)
    | otherwise = ItDoesnt

decVal :: (Ord a, Num a) => a -> WhoCares a
decVal x
    | x - 1 >= 0 = return (x - 1)
    | otherwise = ItDoesnt

main = do
    -- fmap id == id
    let funcx = fmap id "Hi Julie"
    let funcy = id "Hi Julie"
    print(funcx)
    print(funcy)
    print(funcx == funcy)

    -- fmap (f . g) == fmap f . fmap g
    let funcx' = fmap ((+1) . (*2)) [1..5]
    let funcy' = fmap (+1) . fmap (*2) $ [1..5]
    print(funcx')
    print(funcy')
    print(funcx' == funcy')

    -- pure id <*> v = v
    print(pure id <*> (Matter 10))

    -- pure (.) <*> u <*> v <*> w = u <*> (v <*> w)
    let appx = pure (.) <*> (Matter (+1)) <*> (Matter (*2)) <*> (Matter 10)
    let appy = (Matter (+1)) <*> ((Matter (*2)) <*> (Matter 10))
    print(appx)
    print(appy)
    print(appx == appy)

    -- pure f <*> pure x = pure (f x)
    let appx' = pure (+1) <*> pure 1 :: WhoCares Int
    let appy' = pure ((+1) 1) :: WhoCares Int
    print(appx')
    print(appy')
    print(appx' == appy')

    -- u <*> pure y = pure ($ y) <*> u
    let appx'' = Matter (+2) <*> pure 2
    let appy'' = pure ($ 2) <*> Matter (+ 2)
    print(appx'')
    print(appy'')
    print(appx'' == appy'')

    -- m >>= return = m
    let monx = Matter 20 >>= return
    let mony = Matter 20
    print(monx)
    print(mony)
    print(monx == mony)

    -- return x >>= f = f x
    let monx' = return 20 >>= half
    let mony' = half 20
    print(monx')
    print(mony')
    print(monx' == mony')

    -- (m >>= f) >>= g = m >>= (\x -> f x >>= g)
    let monx'' = return 20 >>= half >>= half
    let mony'' = half 20 >>= half
    print(monx'')
    print(mony'')
    print(monx'' == mony'')

    print (Matter 7 >>= incVal >>= incVal >>= incVal)
    print (Matter 7 >>= incVal >>= incVal >>= incVal >>= incVal)
    print (Matter 7 >>= incVal >>= incVal >>= incVal >>= incVal >>= decVal >>= decVal)
    print (Matter 2 >>= decVal >>= decVal >>= decVal)
    print (Matter 20 >>= half >>= half)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM