1
10
bind并不是一种特殊情况,但通常它将在与monads数据类型相同的模块中定义。因此,它可能知道(和使用)模块未导出的详细信息。通常情况下,模块会导出一个数据类型,但它不是构造函数或有关类型内部结构的其他详细信息。然后,对于使用模块的代码,数据类型的内部工作是不可见的,并且该代码不能直接修改此类型的值。
与模块内定义的函数相反,例如一些绑定运算符
特殊情况是
它实际上不需要与状态变化有关,这只是一个可以用抱怨来处理的问题。这个
一般来说,monad(特别是bind函数)定义了一种方法,在这种方法中,某些函数应该组合成更大的函数。这种组合函数的方法是在monad中抽象出来的。这种组合到底是如何工作的,或者为什么要以这种方式组合函数并不重要,monad只是指定了以某种方式组合某些函数的方法。(也见) this "Monads for C# programmers" answer 我基本上用例子重复了几次。) |
2
12
当然,在bind运算符内部也是可能的,因为它的类型指定了:
monad的“run”函数通常也可以这样做(从计算中返回一个纯值)。
嗯,不,单子让我们模拟计算的概念。副作用计算只是这样一个概念,即状态、回溯、延续、并发性、事务、可选结果、随机结果、可恢复状态、不确定性……所有这些 can be described as a monad 我想IO Monad就是你所指的。它是一个有点奇怪的monad——它生成对世界状态的抽象更改序列,然后由运行时进行评估。bind只是让我们按照IO monad的正确顺序对事物进行排序——然后编译器会将所有这些顺序化的世界修改操作转换成命令式代码,从而改变机器的状态。 这是非常具体的IO Monad虽然,不是一般的Monad。 |
3
5
下面是类型类的定义
类型类的每个类型实例
正如我们看到的,因为
为了完成一个例子,我们可以采取:
除糖后,do符号变为:
其计算结果为:
|
4
4
有趣的是,这些类型确实排成一行。这是怎么回事。 记住monad也是一个函数。为所有函数定义了以下函数:
现在的问题是:这些类型真的排列起来了吗?嗯,是的。给定的函数来自
类比三段论:
现在,如您所知,monad是一个装备了bind和return的函数:
你可能不知道,它是一个装备了返回和连接的函数:
看看我们是如何剥离
现在看第一个论点
实际上,bind和join可以根据彼此定义:
|
5
2
我非常推荐你读( http://blog.sigfpe.com/2006/08/you-could-have-invented-monads-and.html )它给出了一个完美的,常识性的单子存在的原因。 |
6
2
实际上比这更微妙。monads允许我们以一种非常一般的方式对序列进行建模。通常,当你和一个领域专家交谈时,你会发现他们说“首先我们尝试X,然后我们尝试Y,如果这不起作用,那么我们尝试Z”。当你在传统语言中实现类似的东西时,你会发现它不适合,所以你必须编写大量额外的代码来覆盖领域专家所说的“那么”这个词。 在haskell中,您可以将其作为monad实现,并将“then”转换为bind运算符。例如,我曾经写过一个程序,其中一个项目必须根据特定的规则从池中分配。对于案例1,您是从池X中取出的。如果是空的,那么您就转到池Y中。对于案例2,您必须直接从池Y中取出它。对于大约十几个案例,包括您最近从池X或池Y中取用最少的案例。我专门为该作业编写了一个自定义Monad,以便我可以编写:
它工作得很好。 当然,这包括传统的排序模型。IO Monad是所有其他编程语言所拥有的模型;它只是Haskell中的一个明确选择,而不是环境的一部分。st-monad给出了IO的记忆突变,但是没有实际的输入和输出。另一方面,状态monad允许您将状态限制为命名类型的单个值。 关于真正的大脑弯曲,请看 this blog post 关于后向状态Monad。状态的传播方向与“执行”相反。如果您将其视为一个状态单元执行一条指令,然后执行下一条指令,那么“put”将及时将状态值向后发送到前面的任何“get”。什么 事实上 发生的情况是建立了一个相互递归的函数,该函数只有在没有悖论的情况下才会终止。我不太确定在哪里使用这样的monad,但它说明了monad是计算模型的要点。 如果您还没有准备好,那么只需将bind看作一个可重载的分号。这让你走了很长的路。 |