Monad与Join()而不是Bind() [英] Monads with Join() instead of Bind()

查看:145
本文介绍了Monad与Join()而不是Bind()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Monads通常会依次解释 return bind 。但是,我收集你也可以通过 join (和 fmap )来实现 bind

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



我不完全确定我明白<$然而,c $ c> join 可以工作。很显然,它有[Haskell]类型



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

对于monad列表,这很简单,显然 concat 。但对于一般的monad来说,这种方法实际上在做什么呢?我看到它对类型签名有什么作用,但我试图弄清楚如何在Java或类似语言中编写类似的东西。



(实际上,这很容易:我不会,因为泛型被打破了;-)但原则上这个问题仍然存在......)




糟糕。它看起来像之前已经被问过:

Monad join功能



有人可以使用 return fmap 和加入? (也就是说,根本不提及>> = )。我认为也许这可能会帮助它沉入我的愚蠢的大脑......

解决方案

没有探索隐喻的深度,我可能会建议读一个典型的monad m 作为产生一个的策略,因此类型 m值是第一类产生价值的策略。计算或外部交互的不同概念需要不同类型的策略,但是一般概念需要一些规则的结构才有意义:如果您已经有一个值,那么你有一个策略来产生一个值( return :: v - > mv ),除了产生你所拥有的值之外, li>

  • 如果您有一种将某种价值转换为另一种价值的功能,您可以将其提升为策略( fmap ::(v - > u) - > mv - > mu ),只需等待策略传递其价值,然后转换它; 如果您有策略来生成策略以生成值,那么你可以构造一个策略来产生一个遵循外部策略的值( join :: m(mv) - > mv ),直到它产生内部策略,然后将该内部策略一直追踪到一个值。


    让我们举一个例子:叶标签二叉树s ...

     数据树v = Leaf v |节点(树v)(树v)

    ...表示通过掷硬币。如果策略是 Leaf v ,那么您的 v ;如果策略是 Node ht ,那么投掷一枚硬币,如果硬币显示正面,则继续策略 h t 如果是tails。

     实例Monad Tree其中
    return = Leaf

    策略制定策略是一棵带有树状标签的树叶:就位每个这样的叶子,我们可以移植到标签它的树上......

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

    ...当然我们有 fmap ,它们只是重新开始。

      instance Functor其中
    fmap f(Leaf x)= Leaf(fx)
    fmap f(Node ht)= Node(fmap fh)(fmap ft)
    pre>

    以下策略产生一个策略来产生 Int





    投掷一枚硬币:如果它的头,簸另一个硬币两种策略决定之间(产生,分别为抛硬币用于产生0或产生1或产生2);如果它是尾巴产生第三(掷硬币生产3或掷硬币4或5)。

    很明显加入 s制定一个策略来生成 Int





    我们正在使用的是事实上,产生价值的策略本身可以被看作是一种价值。在Haskell中,策略作为值的嵌入是沉默的,但在英语中,我使用引号来区分使用策略与仅仅谈论策略。 加入运算符表达策略以某种方式产生然后遵循策略,或者如果你告诉策略,那么你可以使用它。



    。我不确定这种策略方法是否适合考虑单子和通常的价值/计算的区别,还是它只是另一个可怕的隐喻,我确实发现叶子标记的树状类型是直觉的有用来源,这可能不是一个惊喜,因为它们是 free monads,足够的结构成为单子,但没有更多。)



    PS绑定的类型

     (>> =):: mv  - > (v→m w)→> mw 

    表示如果您有策略产生 v ,并且对于每个后续策略来产生一个 w ,那么你有一个策略来产生一个 w 。我们怎样才能以加入

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

    我们可以重新标记 v2mw 生成策略,而不是每个 v 值生成 w - 制作策略,从它开始 - —准备加入


    Monads are usually explained in turns of return and bind. However, I gather you can also implement bind in terms of join (and fmap?)

    In programming languages lacking first-class functions, bind is excruciatingly awkward to use. join, on the other hand, looks quite easy.

    I'm not completely sure I understand how join works, however. Obviously, it has the [Haskell] type

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

    For the list monad, this is trivially and obviously concat. But for a general monad, what, operationally, does this method actually do? I see what it does to the type signatures, but I'm trying to figure out how I'd write something like this in, say, Java or similar.

    (Actually, that's easy: I wouldn't. Because generics is broken. ;-) But in principle the question still stands...)


    Oops. It looks like this has been asked before:

    Monad join function

    Could somebody sketch out some implementations of common monads using return, fmap and join? (I.e., not mentioning >>= at all.) I think perhaps that might help it to sink in to my dumb brain...

    解决方案

    Without plumbing the depths of metaphor, might I suggest to read a typical monad m as "strategy to produce a", so the type m value is a first class "strategy to produce a value". Different notions of computation or external interaction require different types of strategy, but the general notion requires some regular structure to make sense:

    • if you already have a value, then you have a strategy to produce a value (return :: v -> m v) consisting of nothing other than producing the value that you have;
    • if you have a function which transforms one sort of value into another, you can lift it to strategies (fmap :: (v -> u) -> m v -> m u) just by waiting for the strategy to deliver its value, then transforming it;
    • if you have a strategy to produce a strategy to produce a value, then you can construct a strategy to produce a value (join :: m (m v) -> m v) which follows the outer strategy until it produces the inner strategy, then follows that inner strategy all the way to a value.

    Let's have an example: leaf-labelled binary trees...

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

    ...represent strategies to produce stuff by tossing a coin. If the strategy is Leaf v, there's your v; if the strategy is Node h t, you toss a coin and continue by strategy h if the coin shows "heads", t if it's "tails".

    instance Monad Tree where
      return = Leaf
    

    A strategy-producing strategy is a tree with tree-labelled leaves: in place of each such leaf, we can just graft in the tree which labels it...

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

    ...and of course we have fmap which just relabels leaves.

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

    Here's an strategy to produce a strategy to produce an Int.

    Toss a coin: if it's "heads", toss another coin to decide between two strategies (producing, respectively, "toss a coin for producing 0 or producing 1" or "produce 2"); if it's "tails" produce a third ("toss a coin for producing 3 or tossing a coin for 4 or 5").

    That clearly joins up to make a strategy producing an Int.

    What we're making use of is the fact that a "strategy to produce a value" can itself be seen as a value. In Haskell, the embedding of strategies as values is silent, but in English, I use quotation marks to distinguish using a strategy from just talking about it. The join operator expresses the strategy "somehow produce then follow a strategy", or "if you are told a strategy, you may then use it".

    (Meta. I'm not sure whether this "strategy" approach is a suitably generic way to think about monads and the value/computation distinction, or whether it's just another crummy metaphor. I do find leaf-labelled tree-like types a useful source of intuition, which is perhaps not a surprise as they're the free monads, with just enough structure to be monads at all, but no more.)

    PS The type of "bind"

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

    says "if you have a strategy to produce a v, and for each v a follow-on strategy to produce a w, then you have a strategy to produce a w". How can we capture that in terms of join?

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

    We can relabel our v-producing strategy by v2mw, producing instead of each v value the w-producing strategy which follows on from it — ready to join!

    这篇关于Monad与Join()而不是Bind()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆