The Haskell monad example: explanation of how it works

时间:2017-06-25 20:29:56

标签: haskell monads

madd a b = do aa <- a
              bb <- b
              return (aa + bb)

data Counter a = Counter a Int
    deriving (Show,Eq)

instance Functor Counter where
  fmap f (Counter a i) = Counter (f a) i

instance Applicative Counter where
  pure x = Counter x 0
  Counter f i <*> Counter x j = Counter (f x) (i + j)

instance Monad Counter where
  return x = Counter x 0
  Counter a i >>= f = 
    let Counter b j = f a
     in Counter b (i + j + 1)

So suppose for this code one runs:

 madd (Counter 10 43) (Counter 32 1)

and one gets Counter 42 46.

I do not get how this produces this result. So madd "calls" monad Counter, then passes + function to >>= part of the monad instance. But then I find how the monad instance calls/passes functions/results very puzzling.

Can anyone explain in detail how intermediate calculations work?

2 个答案:

答案 0 :(得分:1)

tl; dr :拥抱do,避开 bind !无论如何,这是一个实施细节。 do可以真正被视为一种公理化的主要符号,因为&#34; monads&#34; 首先说出"programs"是一种奇特的方式(< em>在这里插入对冲限定符)。

do表示法移植到基于 bind 的代码中,

do { v <- m ; f v }  ===  m >>= f

相反,反方向,

Counter a i >>= f  ===  do { v <- Counter a i ; f v }

因此,您的Monad实例绑定定义,

Counter a i >>= f  =  Counter b (i + j + 1)  where
                      Counter b j = f a

可以非正式地重写为

instance Monad Counter where
  return x      =  Counter x 0
  do { v <- Counter x i
     ; f v }    =  Counter y (i + j + 1)  where        -- the bind transformation
                   Counter y j = f v
                   v           = x

现在我们可以直接操作您的do代码,看看发生了什么:

madd (Counter 10 43) (Counter 32 1)
= do { aa <- Counter 10 43
     ; bb <- Counter 32 1
     ; return (aa + bb)
     }
= do { aa <- Counter 10 43
     ; do { bb <- Counter 32 1                         -- by Monad Laws
          ; return (aa + bb)
          }}
= do { aa <- Counter 10 43
     ; f aa } where f aa = do { bb <- Counter 32 1     -- abstraction
                              ; return (aa + bb)
                              }
= Counter y (43 + j + 1)                               -- the bind transformation
  where Counter y j = f 10
                    = do { bb <- Counter 32 1
                         ; return (10 + bb)
                         }
                    = do { bb <- Counter 32 1
                         ; (return . (10 +)) bb
                         }
                    = Counter y (1 + j + 1)            -- the bind transformation
                      where Counter y j = (return . (10 +)) 32
                                        =  return 42
                                        = Counter 42 0
                    = Counter 42 (1 + 0 + 1)
                    = Counter 42 2
= Counter 42 (43 + 2 + 1)
= Counter 42 46 

即,madd (Counter a i) (Counter b j)生成Counter (a+b) (i+j+2) 2 bind 转换应用程序的数量。

答案 1 :(得分:0)

当您do madd中的a >>= \aa -> b >>= \bb -> return (a + b) 表达式变为

Awesomium.Core.AweInvalidOperationException: 'The calling thread cannot access this object because a different thread owns it.'

所以你从第一个和第二个计数器得到43加1加上两个,每个为madd

中的每个绑定

学习monad时,最好避免使用符号,并始终记住我们正在分析的monad的bind(&gt;&gt; =)的具体定义