代码之家  ›  专栏  ›  技术社区  ›  Casebash

单元联接函数

  •  25
  • Casebash  · 技术社区  · 15 年前

    虽然monad是使用bind和return函数在haskell中表示的,但是它们也可以使用join函数进行另一种表示,例如 discussed here . 我知道这个函数的类型是m(m(x))->m(x),但它实际上是做什么的?

    5 回复  |  直到 8 年前
        1
  •  37
  •   C. A. McCann Ravikant Cherukuri    15 年前

    实际上,在某种程度上, join 是所有魔法真正发生的地方吗-- (>>=) 主要是为了方便使用。

    所有 Functor -基于类型类使用某种类型描述附加结构。用 函子 这种额外的结构通常被认为是一个“容器”,而 Monad 它往往被认为是“副作用”,但那些只是(偶尔误导性的)速记——不管是哪种方式,都是一样的,没有什么特别之处。 〔0〕 .

    的显著特征 单子 与其他人相比 函子 S是它可以嵌入 控制流 进入额外的结构。它能做到这一点的原因是,不同于 fmap 在整个结构上应用单一的平面函数, (& gt;& gt;=) 检查单个元素并构建 新的 结构。

    与平原 函子 ,从原始结构的每一块构建新结构将替代 函子 ,每个层代表一个控制流点。这显然限制了实用性,因为结果是混乱的,并且具有反映所使用的流控制结构的类型。

    一元“副作用”是具有一些附加性质的结构。 〔1〕 :

    • 两个副作用可分为一组(例如,“do x”和“do y”变为“do x,then y”),只要维持副作用的顺序,分组顺序就不重要。
    • 存在“不做任何事情”副作用(例如,“做X”和“不做任何事情”分组与“做X”相同)

    这个 参加 函数只不过是该分组操作:类似于 m (m a) 描述两种副作用及其发生的顺序,以及 参加 把它们组合成一个单一的副作用。

    因此,对于一元副作用而言,bind操作是“取一个具有相关副作用的值和一个引入新副作用的函数,然后将该函数应用于该值,同时组合每个副作用”。

    〔0〕: 除了 IO . 输入输出 非常 特殊的。

    〔1〕: 如果将这些属性与 Monoid 你会看到这两者之间的相似之处,这不是巧合,事实上,这就是“内函数类中的一个单倍体,有什么问题?”行正在引用。

        2
  •  26
  •   Peter Milley    15 年前

    什么连接 我想,到目前为止,其他答案已经充分描述过了。如果你在寻找一种更直观的理解……如果你想知道“join”的意思是什么……那么不幸的是,答案会因所讨论的monad而有所不同,具体取决于m(x)“的意思”和m(m(x))“的意思”。

    如果m是单子列表,那么m(m(x))是列表列表,join意味着“展平”。如果m是可能的monad,那么m(m(x))的元素可以是“just(just x)”、“just nothing”或“nothing”,join意味着以逻辑方式将这些结构分别折叠为“just x”、“nothing”和“nothing”(类似于camcann对join的组合副作用的回答)。

    对于更复杂的单子,m(m(x))变得非常抽象,决定m(m(x))和连接“mean”变得更加复杂。在每一种情况下,它都有点像单子列表的情况,因为您将两个单子抽象层折叠成一个层,但是含义会有所不同。对于状态单子,camcann结合两个副作用的答案是bang-on:join本质上意味着结合两个连续的状态转换。连续单子是特别令人头疼的,但是数学上的连接实际上是相当整洁的:m(x)对应于x的“双对偶空间”,数学家可能会这样写。 X** (延续本身,即x->r的映射,其中r是一组最终结果,对应于单个双空间 X* 和join对应于来自 X**** x** . 连续单子满足单子定律的事实对应于一个数学事实,即应用对偶空间算符通常没有多大意义。 * 两次以上。

    但我离题了。

    就我个人而言,我试图抵制将一个单一的类比应用于所有可能的单子类型的冲动;单子的概念太笼统,无法用单一的描述性类比来区分。join的含义将根据您在任何给定时间使用的类比而有所不同。

        3
  •  6
  •   ase    15 年前

    从同一页恢复此信息 join x = x >>= id ,了解 bind id 功能正常,你应该能够找出 join 做。

        4
  •  5
  •   Daniel Pratt    15 年前

    从概念上讲,它的作用可以通过查看类型来确定:它展开或扁平外部一元容器/计算,并返回其中生成的一元值。

    它实际上是如何做到的,这取决于你正在处理的单子类型。例如,对于列表monad,“join”等同于 concat .

        5
  •  1
  •   RomnieEE    8 年前

    绑定操作映射: ma -> (a -> mb) -> mb . 在 ma 和(第一) mb 我们有两个 m 根据我的直觉,理解绑定和单元操作在很大程度上是在理解这两个操作以及它们是如何实现的。 S(单上下文实例)将被合并。我喜欢把作家Monad看作是理解 join . 写入程序可用于记录操作。 妈妈 有一个日志。 (a -> mb) 将首先生成另一个登录 MB . 第二 MB 合并这两个日志。

    (一个不好的例子是可能的单子,因为 Just + 只是 = 只是 Nothing 什么都可以 没有什么 (或F) Some None )是如此的不具建设性,你忽略了一个事实,那就是一些重要的事情正在发生。你可能会想到 只是 作为一个简单的条件进行和 没有什么 仅仅是一个停止的标志。就像路上的路标,在计算过程中留下的。(这是自决赛以来的合理印象 只是 没有什么 似乎是在计算的最后一步从头开始创建的,没有从前面的步骤转移到它里面。)当你真的需要关注 只是 S和 没有什么 每次都是这样。)

    这个问题为我在阅读Miran Lipovaca的《好好学你一个哈斯克尔》中明确指出!第12章,单子法的最后一节。 http://learnyouahaskell.com/a-fistful-of-monads#monad-laws ,关联性。这一要求是:“做 (ma >>= f) >>= g 就像在做 ma >>= (\x -> f x >>= g) [我使用 妈妈 对于 “好吧,在双方,争论首先传递给 f 然后到 g . 那么他说的“不容易看出这两个是如何平等的”是什么意思呢?不容易看出它们是如何不同的!

    区别在于 参加 对… S(上下文)--哪个 bind 有,还有地图。捆绑打开或绕过 到达 a 哪一个 f 应用于——但这并不是全部。第一 (上) 妈妈 举行时 f 产生一秒钟 (上) MB )然后 绑定 组合—— 参加 两者兼而有之 美国的关键 绑定 是一样多的在 参加 因为它在打开( map )我觉得困惑 参加 表示固定在 绑定 ——得到 由于 妈妈 为了匹配的签名 f 他的论点——忽略了这两个事实 S(从 妈妈 然后 MB )需要和解。(丢弃第一个 可能是在某些情况下处理它的适当方法(可能),但一般来说这不是正确的——正如作者所说明的那样。)

    在左边,我们 绑定 妈妈 f 首先,然后 G 第二。所以日志如下: ("before f" + "after f") + "after g" . 在右边,而函数 f G 按同样的顺序申请,现在我们 绑定 G 第一。所以日志如下: "before f" + ("after f" + "after g") . parens不在字符串中,因此日志的任何一种方式都是相同的,并且遵守了规律。(然而,如果第二根圆木 "after f" + "after g" + "before f" --那么我们就会陷入数学困境了!).

    重铸 绑定 作为 fmap 参加 对于作家来说,我们 fmap f ma 在哪里 f:a -> mb 导致 m(mb) . 想想第一个 妈妈 如“F前”。这个 f 应用于 先在里面 现在请稍等 (或) MB )到达——在第一个里面 ,其中映射 f 发生。想想第二个 MB “F后”。 M(MB) =(“F前”(“F后”)。 b )现在我们使用join来折叠两个日志, S,做一个新的 . 作者使用了一个monoid,我们将其连接起来。其他单子以其他方式结合上下文——遵守法律。这可能是理解它们的主要部分。