gpt4 book ai didi

haskell - 如何将 Monad 实例定义为具有多个值的类型?

转载 作者:行者123 更新时间:2023-12-04 10:14:57 24 4
gpt4 key购买 nike

通过多个值,我的意思是这样的:

data Foo a = Bar a | Baz a a

我想不出一个明确的方法来定义 >>=对于 Baz :
instance Monad Foo where
Bar x >>= f = f x -- Great, that works perfectly!
Baz x y >>= f = ??? -- What the heck do I even put here?

最佳答案

也许:

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))

这个定义的灵感来自于 (>>=) 的定义。对于 (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

编辑 好的,我决定写一个简短的解释,说明这是如何受到 (Bool ->) 启发的。即使没有人问。所以,回想一下:
instance Monad (e ->) where
m >>= f = \e -> f (m e) e

现在我们要定义
data Pair a = Pair a a

并观察 Bool -> aPair 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)

原来 fromto是同构。换句话说:你可以交替想到 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

和:
  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 .

编辑 2 另一个(不同的!)monad 是可能的。从 base 中检查同构类型的行为:
type Foo = Product Identity Maybe

the docs for 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

从某种意义上说,我最初的提议“扩展”了结果的数量,因为你添加了更多的单子(monad) Action ——从 Bar 开始。在 return并转换 Bar不可撤销地发送给 Baz s 在绑定(bind)中——虽然这个实例“收缩”了可能的结果数量,因为你添加了更多的单子(monad) Action ——从 Baz 开始在 return并转换 Baz转至 Bar不可撤销地处于束缚之中。如果你问我,这是一个非常有趣的设计选择!这也让我想知道是否还有一个 Monad Product 的实例是可能的(可能对所涉及的仿函数有不同的约束)。

关于haskell - 如何将 Monad 实例定义为具有多个值的类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43684258/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com