Haskell Monad示例:解释其工作原理


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)

所以假设此代码运行:

 madd (Counter 10 43) (Counter 32 1)

一个人获得Counter 42 46

我不知道这是如何产生此结果的。因此, madd"调用" monad Counter,然后将 +函数传递到单一实例的>>=。但是后来我找到了单元实例如何调用/传递功能/结果非常困惑。

任何人都可以详细解释中间计算的工作方式吗?

tl; dr &#8202;:拥抱do,避开 bind &#8202;!无论如何,这是一个实施细节。do确实可以视为公理的主要符号,如" monads" 是首先说" program" 的一种方式(插入a对冲预选赛(。


do符号被列为 bind &#8202;基代码,

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

相反,沿反向方向

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

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

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

Now we can manipulate your do code directly, to see what's going on:

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 

that is, madd (Counter a i) (Counter b j) produces Counter (a+b) (i+j+2), 2 being the number of bind transformation applications.

When desugared your do expression in madd becomes

a >>= aa -> b >>= bb -> return (a + b)

因此,您可以从第一和第二计数器加两个,每个都有43加1,每个计数器都在madd中绑定

学习单子时,避免执行表示法是一个好主意,并始终记住单核的绑定(>> =(的特定定义,我们正在分析

最新更新