haskell - 使用 Join() 而不是 Bind() 的 Monad

标签 haskell monads

Monad 通常按 returnbind 的顺序进行解释。但是,我认为您也可以根据 join 实现 bind (和 fmap?)

在缺乏一流函数的编程语言中,bind 使用起来极其尴尬。另一方面,join 看起来相当简单。

但是,我并不完全确定我理解 join 的工作原理。显然,它具有[Haskell]类型

join :: Monad m => m (m x) -> m x

对于列表 monad,这是简单且明显的concat。但对于一般的 monad,从操作上来说,这个方法实际上做了什么?我了解它对类型签名的作用,但我正在尝试弄清楚如何在 Java 或类似语言中编写类似的内容。

(实际上,这很简单:我不会。因为泛型已损坏。;-)但原则上问题仍然存在......)

<小时/>

哎呀。看起来以前已经问过这个问题:

Monad join function

有人可以使用 returnfmapjoin 勾勒出常见 monad 的一些实现吗? (即,根本不提及 >>=。)我认为这可能有助于它深入到我愚蠢的大脑中......

最佳答案

在不深入隐喻的情况下,我是否可以建议将典型的单子(monad) m 解读为“生成 a 的策略”,因此类型 m 值 是一流的“创造值(value)的策略”。不同的计算或外部交互概念需要不同类型的策略,但一般概念需要一些规则的结构才能有意义:

  • 如果您已经有一个值,那么您就有一个策略来生成一个值 (return::v -> m v),该值除了生成您拥有的值之外什么也不包含;
  • 如果您有一个将一种值转换为另一种值的函数,您只需等待即可将其提升为策略 (fmap::(v -> u) -> m v -> m u)让战略实现其值(value),然后对其进行转型;
  • 如果您有一个策略来生成一个策略来生成一个值,那么您可以构造一个策略来生成一个值 (join::m (m v) -> m v),该策略遵循外部策略,直到它产生内部策略,然后遵循该内部策略一直到一个值。

让我们举个例子:叶子标记的二叉树...

data Tree v = Leaf v | Node (Tree v) (Tree v)

...代表通过抛硬币来生产东西的策略。如果策略是Leaf v,那就是你的v;如果策略是Node h t,则抛一枚硬币,如果硬币显示“正面”,则继续策略h;如果硬币显示“反面”,则继续策略t ”。

instance Monad Tree where
  return = Leaf

生成策略的策略是一棵带有树标记叶子的树:我们可以将每个这样的叶子移植到标记它的树中......

  join (Leaf tree) = tree
  join (Node h t)  = Node (join h) (join t)

...当然我们有 fmap 它只是重新标记叶子。

instance Functor Tree where
  fmap f (Leaf x)    = Leaf (f x)
  fmap f (Node h t)  = Node (fmap f h) (fmap f t)

这是一个生成 Int 的策略。

tree of trees

抛一枚硬币:如果是“正面”,则再抛一枚硬币以在两种策略之间做出决定(分别产生“抛硬币产生 0 或产生 1”或“产生 2”);如果是“反面”,则产生第三个(“抛硬币产生 3 或抛硬币产生 4 或 5”)。

很明显,join是为了制定一个生成Int的策略。

enter image description here

我们利用的是这样一个事实:“产生值(value)的策略”本身就可以被视为一种值(value)。在 Haskell 中,策略作为值的嵌入是沉默的,但在英语中,我使用引号来区分使用策略和仅仅谈论它。 join 运算符表达了“以某种方式产生然后遵循策略”的策略,或者“如果您被告知一个策略,那么您可以使用它” ”。

(元。我不确定这种“策略”方法是否是思考单子(monad)和值/计算区别的通用方法,或者它是否只是另一个糟糕的隐喻。我确实发现叶子标记的树状结构类型是直觉的有用来源,这也许并不奇怪,因为它们是免费单子(monad),具有足够的结构作为单子(monad),但仅此而已。)

PS“绑定(bind)”的类型

(>>=) :: m v -> (v -> m w) -> m w

表示“如果您有一个生成 v 的策略,并且对于每个 v 有一个生成 w 的后续策略,那么您就有一个生成w”。我们如何通过 join 来捕捉这一点?

mv >>= v2mw = join (fmap v2mw mv)

我们可以通过 v2mw 重新标记我们的 v 生成策略,生成 w 而不是每个 v 值- 制定随之而来的策略 - 准备加入!

关于haskell - 使用 Join() 而不是 Bind() 的 Monad,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11234632/

相关文章:

haskell - 重新定义列表 monad 实例

Hoogle 的 EclipseFP 问题

scala - 在scala中堆叠Monad Transformers

haskell - 函数应用作为身份 Monad : how is it an instance of the Monad typeclass?

haskell - 让 IO 成为 MonadCont 的实例有意义吗?

Haskell:I/O 和从函数返回

haskell - 惰性数据类型的内存使用情况

haskell - mapM 和 forM 可以互换吗?

haskell - 从依赖包的测试套件导入模块

Haskell:重复函数(+)和(++),mappend