Haskell monad 示例:解释它是如何工作的
The Haskell monad example: explanation of how it works
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
"calls" monad Counter
,然后将 +
函数传递给 monad 实例的 >>=
部分。但是后来我发现 monad 实例 calls/passes functions/results 非常令人费解。
谁能详细解释中间计算的工作原理?
脱糖后,madd
中的 do
表达式变为
a >>= \aa -> b >>= \bb -> return (a + b)
所以你从第一个和第二个计数器得到 43 加 1 加 2,每个都对应 madd 中的每个绑定
学习 monad 时,最好避免 do 表示法,并始终记住我们正在分析的 monad 的绑定 (>>=) 的具体定义
tl;dr :拥抱 do
,避开 bind !无论如何,这是一个实施细节。 do
确实可以被视为公理化的基本符号,因为 "monads" 首先是 的一种奇特方式(在此处插入对冲限定符)。
do
符号被脱糖到基于 bind 的代码中,
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 <b>x</b> = Counter <b>x</b> 0
do { v <- Counter <b>x</b> <i>i</i>
; f v } = Counter y (<i>i</i> + j + 1) where -- the <em>bind</em> transformation
Counter y j = f v
v = <strong>x</strong></pre>
现在我们可以直接操作您的 do
代码,看看发生了什么:
madd (Counter <b>10</b> <em>43</em>) (Counter <b>32</b> <em>1</em>)
= do { aa <- Counter <b>10</b> <em>43</em>
; bb <- Counter <b>32</b> <em>1</em>
; return (aa + bb)
}
= do { aa <- Counter <b>10</b> <em>43</em>
; do { bb <- Counter <b>32</b> <em>1</em> -- by Monad Laws
; return (aa + bb)
}}
= do { aa <- Counter <b>10</b> <em>43</em>
; f aa } where f aa = do { bb <- Counter <b>32</b> <em>1</em> -- abstraction
; return (aa + bb)
}
= Counter y (<em>43</em> + j + 1) -- the <em>bind</em> transformation
where Counter y j = f <b>10</b>
= do { bb <- Counter <b>32</b> <em>1</em>
; return (<b>10</b> + bb)
}
= do { bb <- Counter <b>32</b> <em>1</em>
; (return . (<b>10</b> +)) bb
}
= Counter y (<em>1</em> + j + 1) -- the <em>bind</em> transformation
where Counter y j = (return . (<b>10</b> +)) <b>32</b>
= return 42
= Counter 42 0
= Counter 42 (<em>1</em> + 0 + 1)
= Counter 42 2
= Counter 42 (<em>43</em> + 2 + 1)
= Counter 42 46 </pre>
也就是说,madd (Counter a i) (Counter b j)
产生Counter (a+b) (i+j+2)
,2是bind转换应用的数量。
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
"calls" monad Counter
,然后将 +
函数传递给 monad 实例的 >>=
部分。但是后来我发现 monad 实例 calls/passes functions/results 非常令人费解。
谁能详细解释中间计算的工作原理?
脱糖后,madd
中的 do
表达式变为
a >>= \aa -> b >>= \bb -> return (a + b)
所以你从第一个和第二个计数器得到 43 加 1 加 2,每个都对应 madd 中的每个绑定
学习 monad 时,最好避免 do 表示法,并始终记住我们正在分析的 monad 的绑定 (>>=) 的具体定义
tl;dr :拥抱 do
,避开 bind !无论如何,这是一个实施细节。 do
确实可以被视为公理化的基本符号,因为 "monads" 首先是
do
符号被脱糖到基于 bind 的代码中,
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 <b>x</b> = Counter <b>x</b> 0 do { v <- Counter <b>x</b> <i>i</i> ; f v } = Counter y (<i>i</i> + j + 1) where -- the <em>bind</em> transformation Counter y j = f v v = <strong>x</strong></pre>
现在我们可以直接操作您的
do
代码,看看发生了什么:madd (Counter <b>10</b> <em>43</em>) (Counter <b>32</b> <em>1</em>) = do { aa <- Counter <b>10</b> <em>43</em> ; bb <- Counter <b>32</b> <em>1</em> ; return (aa + bb) } = do { aa <- Counter <b>10</b> <em>43</em> ; do { bb <- Counter <b>32</b> <em>1</em> -- by Monad Laws ; return (aa + bb) }} = do { aa <- Counter <b>10</b> <em>43</em> ; f aa } where f aa = do { bb <- Counter <b>32</b> <em>1</em> -- abstraction ; return (aa + bb) } = Counter y (<em>43</em> + j + 1) -- the <em>bind</em> transformation where Counter y j = f <b>10</b> = do { bb <- Counter <b>32</b> <em>1</em> ; return (<b>10</b> + bb) } = do { bb <- Counter <b>32</b> <em>1</em> ; (return . (<b>10</b> +)) bb } = Counter y (<em>1</em> + j + 1) -- the <em>bind</em> transformation where Counter y j = (return . (<b>10</b> +)) <b>32</b> = return 42 = Counter 42 0 = Counter 42 (<em>1</em> + 0 + 1) = Counter 42 2 = Counter 42 (<em>43</em> + 2 + 1) = Counter 42 46 </pre>
也就是说,
madd (Counter a i) (Counter b j)
产生Counter (a+b) (i+j+2)
,2是bind转换应用的数量。