为什么我们需要单子? [英] Why do we need monads?

查看:38
本文介绍了为什么我们需要单子?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我看来,这个著名问题的答案什么是 monad?",尤其是投票最多的那些,尝试解释什么是 monad,但没有清楚地解释为什么 monad 真的是必要的.能否将它们解释为问题的解决方案?

In my humble opinion the answers to the famous question "What is a monad?", especially the most voted ones, try to explain what is a monad without clearly explaining why monads are really necessary. Can they be explained as the solution to a problem?

推荐答案

为什么我们需要 monad?

  1. 我们希望仅使用函数进行编程.(毕竟是函数式编程 (FP)").
  2. 然后,我们遇到了第一个大问题.这是一个程序:

  1. We want to program only using functions. ("functional programming (FP)" after all).
  2. Then, we have a first big problem. This is a program:

f(x) = 2 * x

g(x,y) = x/y

我们怎么说先执行什么?我们如何才能形成一个有序的函数序列(即程序)只使用函数?

How can we say what is to be executed first? How can we form an ordered sequence of functions (i.e. a program) using no more than functions?

解决方案:组合函数.如果你想要先g然后f,只需写f(g(x,y)).这样,程序"也是一个函数:main = f(g(x,y)).好的,但是...

Solution: compose functions. If you want first g and then f, just write f(g(x,y)). This way, "the program" is a function as well: main = f(g(x,y)). OK, but ...

更多问题:某些函数可能会失败(即g(2,0),除以0).我们在 FP 中没有异常"(异常不是函数).我们如何解决?

More problems: some functions might fail (i.e. g(2,0), divide by 0). We have no "exceptions" in FP (an exception is not a function). How do we solve it?

解决方案:让我们允许函数返回两种东西:而不是让 g : Real,Real ->Real(从两个实数到一个实数的函数),让我们允许 g : Real,Real ->真实 |无(从两个实数变为(实数或无)).

Solution: Let's allow functions to return two kind of things: instead of having g : Real,Real -> Real (function from two reals into a real), let's allow g : Real,Real -> Real | Nothing (function from two reals into (real or nothing)).

但是函数应该(为了更简单)只返回一件事.

But functions should (to be simpler) return only one thing.

解决方案:让我们创建一种新的要返回的数据类型,一种装箱类型",它可能包含一个真实的或根本没有的数据.因此,我们可以有 g : Real,Real ->也许是真实的.好的,但是...

Solution: let's create a new type of data to be returned, a "boxing type" that encloses maybe a real or be simply nothing. Hence, we can have g : Real,Real -> Maybe Real. OK, but ...

f(g(x,y)) 现在发生了什么?f 还没有准备好使用 Maybe Real.而且,我们不想改变我们可以与 g 连接的每个函数来使用 Maybe Real.

What happens now to f(g(x,y))? f is not ready to consume a Maybe Real. And, we don't want to change every function we could connect with g to consume a Maybe Real.

解决方案:让我们有一个特殊的功能来连接"/撰写"/链接"功能.这样,我们就可以在幕后调整一个函数的输出来满足下一个函数的需求.

Solution: let's have a special function to "connect"/"compose"/"link" functions. That way, we can, behind the scenes, adapt the output of one function to feed the following one.

在我们的例子中:g >>= f(连接/组合 gf).我们希望 >>= 得到 g 的输出,检查它,如果它是 Nothing 就不要调用 f 并返回 Nothing;或者相反,提取装箱的 Real 并用它提供 f.(这个算法只是对 Maybe 类型的 >>>= 的实现).另请注意,对于每个装箱类型"(不同的框,不同的适应算法),>>= 必须只写一次.

In our case: g >>= f (connect/compose g to f). We want >>= to get g's output, inspect it and, in case it is Nothing just don't call f and return Nothing; or on the contrary, extract the boxed Real and feed f with it. (This algorithm is just the implementation of >>= for the Maybe type). Also note that >>= must be written only once per "boxing type" (different box, different adapting algorithm).

出现的许多其他问题都可以使用相同的模式解决: 1. 使用框"来编码/存储不同的含义/值,并使用诸如 g 之类的函数返回这些盒装值".2. 有一个 composer/linker g >>= f 来帮助将 g 的输出连接到 f 的输入,所以我们根本不需要更改任何 f.

Many other problems arise which can be solved using this same pattern: 1. Use a "box" to codify/store different meanings/values, and have functions like g that return those "boxed values". 2. Have a composer/linker g >>= f to help connecting g's output to f's input, so we don't have to change any f at all.

使用这种技术可以解决的显着问题是:

Remarkable problems that can be solved using this technique are:

  • 具有函数序列中的每个函数(程序")可以共享的全局状态:解决方案StateMonad.

我们不喜欢不纯函数":为相同输入产生不同输出的函数.因此,让我们标记这些函数,使它们返回一个标记/装箱的值:IO monad.

We don't like "impure functions": functions that yield different output for same input. Therefore, let's mark those functions, making them to return a tagged/boxed value: IO monad.

完全的幸福!

这篇关于为什么我们需要单子?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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