Perhaps:
frst (Bar a) = a
frst (Baz a a') = a
scnd (Bar a) = a
scnd (Baz a a') = a'
instance Monad Foo where
return = Bar
Bar x >>= f = f x
Baz x y >>= f = Baz (frst (f x)) (scnd (f y))
这个定义的灵感来自于定义(>>=)
for (Bool ->)
。如果不清楚怎么办就问我。
让我们检查一下法律。这 ”return
是单位”定律非常简单:
return x >>= f
= Bar x >>= f
= f x
m >>= return
= case m of
Bar x -> return x
Baz x y -> Baz (frst (return x)) (scnd (return y))
= case m of
Bar x -> Bar x
Baz x y -> Baz x y
= m
我相信我已经说服自己“(>>=)
也是结合律”,但我确信这个证明对其他人来说是完全无法阅读的……我鼓励你尝试自己证明它,如果你遇到困难,可以将我的计算作为备忘单参考。
m >>= (\v -> f v >>= g)
= case m of
Bar x -> (\v -> f v >>= g) x
Baz x y -> Baz (frst ((\v -> f v >>= g) x))
(scnd ((\v -> f v >>= g) y))
= case m of
Bar x -> f x >>= g
Baz x y -> Baz (frst (f x >>= g)) (scnd (f y >>= g))
= case m of
Bar x -> case f x of
Bar y -> g y
Baz a b -> Baz (frst (g a)) (scnd (g b))
Baz x y -> Baz (frst l) (scnd r) where
l = case f x of
Bar a -> g a
Baz a b -> Baz (frst (g a)) (scnd (g b))
r = case f y of
Bar a -> g a
Baz a b -> Baz (frst (g a)) (scnd (g b))
= case m of
Bar x -> case f x of
Bar y -> g y
Baz a b -> Baz (frst (g a)) (scnd (g b))
Baz x y -> Baz (frst (g (frst (f x))))
(scnd (g (scnd (f y))))
= case m of
Bar a -> case f a of
Bar x -> g x
Baz x y -> Baz (frst (g x)) (scnd (g y))
Baz a b -> case Baz (frst (f a)) (scnd (f b)) of
Bar x -> g x
Baz x y -> Baz (frst (g x)) (scnd (g y))
= case v of
Bar x -> g x
Baz x y -> Baz (frst (g x)) (scnd (g y))
where v = case m of
Bar a -> f a
Baz a b -> Baz (frst (f a)) (scnd (f b))
= case m >>= f of
Bar x -> g x
Baz x y -> Baz (frst (g x)) (scnd (g y))
= (m >>= f) >>= g
edit好吧,我决定写一个简短的解释来解释这是如何受到启发的(Bool ->)
尽管没有人问。所以,回想一下:
instance Monad (e ->) where
m >>= f = \e -> f (m e) e
现在我们要定义
data Pair a = Pair a a
并观察到Bool -> a
and Pair a
非常相似:
to :: Pair a -> (Bool -> a)
to (Pair false true) = \bool -> case bool of
False -> false
True -> true
from :: (Bool -> a) -> Pair a
from f = Pair (f False) (f True)
事实证明from
and to
是同构。换句话说:你可以交替地想到Bool -> a
作为“二元容器”。好吧,如果我们尝试翻译会发生什么(e ->)
实例为Monad
进入Pair
类型?这当然应该是可能的,因为它们是同构的。事实上,我们先从同构开始:
instance Monad Pair where
return x = from (return x)
m >>= f = from (to m >>= to . f)
现在我们可以“转动曲柄”:
return x
= from (return x)
= from (\e -> x)
= Pair ((\e -> x) False) ((\e -> x) True)
= Pair x x
and:
m@(Pair false true) >>= f
= from (to m >>= to . f)
= from (\e -> (to . f) (to m e) e)
= from (\e -> to (f (to m e)) e)
= Pair (g False) (g True) where
g = \e -> to (f (to m e)) e
= Pair (to (f (to m False)) False) (to (f (to m True)) True)
= Pair (case f (to m False) of Pair false true -> false)
(case f (to m True ) of Pair false true -> true )
= Pair (case f false of Pair false true -> false)
(case f true of Pair false true -> true )
所以我们现在可以重写实例而不依赖于(Bool ->)
只需复制并粘贴上述计算的第一行和最后一行:
frstPair (Pair false true) = false
scndPair (Pair false true) = true
instance Monad Pair where
return x = Pair x x
Pair false true >>= f = Pair (frstPair (f false)) (scndPair (f true))
希望您能认识到这与定义有多么相似(>>=)
我在上面给出了Foo
.
edit 2另一个(不同的!)单子是可能的。从基类检查同构类型的行为:
type Foo = Product Identity Maybe
See 的文档Product。如果没有同构,则为:
instance Monad Foo where
return x = Baz x x
Bar x >>= f = Bar (frst (f x))
Baz x y >>= f = case f y of
Bar a -> Bar (frst (f x))
Baz a b -> Baz (frst (f x)) b
从某种意义上说,当您添加更多单子操作时,我最初的提议“扩展”了结果的数量 - 从Bar
in return
并转换Bar
不可撤销地Baz
s 处于绑定状态 - 当您添加更多单子操作时,此实例会“收缩”可能的结果数量 - 从 a 开始Baz
in return
并转换Baz
s to Bar
不可挽回地陷入困境。如果你问我的话,这是一个非常有趣的设计选择!这也让我想知道是否还有另一个Monad
实例为Product
是可能的(可能对所涉及的函子有不同的约束)。