Monad 是简单的英语吗?(对于没有FP背景的OOP程序员)

本文介绍了Monad 是简单的英语吗?(对于没有FP背景的OOP程序员)的处理方法,对大家解决问题具有一定的参考价值

问题描述

用 OOP 程序员(没有任何函数式编程背景)理解的术语来说,什么是 monad?

它解决了什么问题,最常用的地方是什么?

What problem does it solve and what are the most common places it's used?

为了澄清我一直在寻找的那种理解,假设您正在将具有 monad 的 FP 应用程序转换为 OOP 应用程序.您将如何将 monad 的职责移植到 OOP 应用程序中?

To clarify the kind of understanding I was looking for, let’s say you were converting an FP application that had monads into an OOP application. What would you do to port the responsibilities of the monads to the OOP app?

推荐答案

更新:这个问题是一个非常长的博客系列的主题,你可以在 Monads — 感谢您提出的好问题!

UPDATE: This question was the subject of an immensely long blog series, which you can read at Monads — thanks for the great question!

对于 OOP 程序员而言(没有任何函数式编程背景),什么是 monad?

In terms that an OOP programmer would understand (without any functional programming background), what is a monad?

monad 是类型的放大器",它遵守某些规则并且提供某些操作.

A monad is an "amplifier" of types that obeys certain rules and which has certain operations provided.

首先,什么是类型放大器"?我的意思是一些系统可以让您获取一种类型并将其转换为更特殊的类型.例如,在 C# 中考虑 Nullable.这是一个放大器类型.它允许您采用一个类型,例如 int,并为该类型添加一个新功能,即,现在它可以为 null,而之前不能为 null.

First, what is an "amplifier of types"? By that I mean some system which lets you take a type and turn it into a more special type. For example, in C# consider Nullable<T>. This is an amplifier of types. It lets you take a type, say int, and add a new capability to that type, namely, that now it can be null when it couldn't before.

作为第二个例子,考虑 IEnumerable.它是一种放大器.它允许您采用一种类型,例如 string,并为该类型添加新功能,即您现在可以从任意数量的单个字符串中生成一系列字符串.

As a second example, consider IEnumerable<T>. It is an amplifier of types. It lets you take a type, say, string, and add a new capability to that type, namely, that you can now make a sequence of strings out of any number of single strings.

什么是特定规则"?简而言之,底层类型上的函数有一种合理的方式来处理放大类型,以便它们遵循函数组合的正常规则.例如,如果您有一个整数函数,请说

What are the "certain rules"? Briefly, that there is a sensible way for functions on the underlying type to work on the amplified type such that they follow the normal rules of functional composition. For example, if you have a function on integers, say

int M(int x) { return x + N(x * 2); }

然后 Nullable 上的相应函数可以使那里的所有操作符和调用以相同的方式"一起工作.

then the corresponding function on Nullable<int> can make all the operators and calls in there work together "in the same way" that they did before.

(这是非常模糊和不精确的;你要求的解释没有假设任何关于函数组合的知识.)

(That is incredibly vague and imprecise; you asked for an explanation that didn't assume anything about knowledge of functional composition.)

什么是操作"?

  1. 有一个单元"操作(有时令人困惑地称为返回"操作),它从一个普通类型中获取一个值并创建等效的 monadic 值.这实质上提供了一种获取未放大类型的值并将其转换为放大类型的值的方法.它可以在面向对象语言中实现为构造函数.

  1. There is a "unit" operation (confusingly sometimes called the "return" operation) that takes a value from a plain type and creates the equivalent monadic value. This, in essence, provides a way to take a value of an unamplified type and turn it into a value of the amplified type. It could be implemented as a constructor in an OO language.

有一个绑定"操作,它接受一个 monadic 值和一个可以转换该值的函数,并返回一个新的 monadic 值.绑定是定义 monad 语义的关键操作.它让我们可以将非放大类型的操作转换为放大类型的操作,遵守前面提到的函数组合规则.

There is a "bind" operation that takes a monadic value and a function that can transform the value, and returns a new monadic value. Bind is the key operation that defines the semantics of the monad. It lets us transform operations on the unamplified type into operations on the amplified type, that obeys the rules of functional composition mentioned before.

通常有一种方法可以将未放大的类型从放大的类型中取出.严格来说,这个操作不需要有一个 monad.(尽管如果您想要一个 comonad,这是必要的.我们不会在本文中进一步考虑这些.)

There is often a way to get the unamplified type back out of the amplified type. Strictly speaking this operation is not required to have a monad. (Though it is necessary if you want to have a comonad. We won't consider those further in this article.)

再次以Nullable为例.您可以使用构造函数将 int 转换为 Nullable.C# 编译器会为您处理大多数可为空的提升",但如果没有,提升转换很简单:一个操作,比如,

Again, take Nullable<T> as an example. You can turn an int into a Nullable<int> with the constructor. The C# compiler takes care of most nullable "lifting" for you, but if it didn't, the lifting transformation is straightforward: an operation, say,

int M(int x) { whatever }

转化为

Nullable<int> M(Nullable<int> x) 
{ 
    if (x == null) 
        return null; 
    else 
        return new Nullable<int>(whatever);
}

Nullable 变回 int 是通过 Value 属性.

And turning a Nullable<int> back into an int is done with the Value property.

功能转换是关键.请注意可空操作的实际语义 - null 上的操作传播 null - 在转换中被捕获.我们可以概括这一点.

It's the function transformation that is the key bit. Notice how the actual semantics of the nullable operation — that an operation on a null propagates the null — is captured in the transformation. We can generalize this.

假设你有一个从 intint 的函数,就像我们原来的 M.你可以很容易地把它变成一个接受 int 并返回一个 Nullable 的函数,因为你可以通过可空构造函数运行结果.现在假设你有这个高阶方法:

Suppose you have a function from int to int, like our original M. You can easily make that into a function that takes an int and returns a Nullable<int> because you can just run the result through the nullable constructor. Now suppose you have this higher-order method:

static Nullable<T> Bind<T>(Nullable<T> amplified, Func<T, Nullable<T>> func)
{
    if (amplified == null) 
        return null;
    else
        return func(amplified.Value);
}

看看你能用它做什么?任何接受一个 int 并返回一个 int 的方法,或者接受一个 int 并返回一个 Nullable 现在可以应用可为空的语义.

See what you can do with that? Any method that takes an int and returns an int, or takes an int and returns a Nullable<int> can now have the nullable semantics applied to it.

此外:假设您有两种方法

Furthermore: suppose you have two methods

Nullable<int> X(int q) { ... }
Nullable<int> Y(int r) { ... }

并且您想编写它们:

Nullable<int> Z(int s) { return X(Y(s)); }

ZXY的组合.但是你不能这样做,因为 X 需要一个 int,而 Y 返回一个 Nullable.但既然你有绑定"操作,你可以做这个工作:

That is, Z is the composition of X and Y. But you cannot do that because X takes an int, and Y returns a Nullable<int>. But since you have the "bind" operation, you can make this work:

Nullable<int> Z(int s) { return Bind(Y(s), X); }

monad 上的绑定操作是使函数在放大类型上的组合起作用的原因. 我在上面提到的规则"是monad 保留了正常函数组合的规则;与恒等函数组合产生原始函数,组合是结合的,等等.

The bind operation on a monad is what makes composition of functions on amplified types work. The "rules" I handwaved about above are that the monad preserves the rules of normal function composition; that composing with identity functions results in the original function, that composition is associative, and so on.

在 C# 中,绑定"称为SelectMany".看看它是如何在序列 monad 上工作的.我们需要做两件事:将值转换为序列和对序列进行绑定操作.作为奖励,我们还有将序列转回值".这些操作是:

In C#, "Bind" is called "SelectMany". Take a look at how it works on the sequence monad. We need to have two things: turn a value into a sequence and bind operations on sequences. As a bonus, we also have "turn a sequence back into a value". Those operations are:

static IEnumerable<T> MakeSequence<T>(T item)
{
    yield return item;
}
// Extract a value
static T First<T>(IEnumerable<T> sequence)
{
    // let's just take the first one
    foreach(T item in sequence) return item; 
    throw new Exception("No first item");
}
// "Bind" is called "SelectMany"
static IEnumerable<T> SelectMany<T>(IEnumerable<T> seq, Func<T, IEnumerable<T>> func)
{
    foreach(T item in seq)
        foreach(T result in func(item))
            yield return result;            
}

可空 monad 规则是将产生可空值的两个函数组合在一起,检查内部函数是否为空;如果是,则产生空值,如果不是,则使用结果调用外部函数".这就是 nullable 所需的语义.

The nullable monad rule was "to combine two functions that produce nullables together, check to see if the inner one results in null; if it does, produce null, if it does not, then call the outer one with the result". That's the desired semantics of nullable.

序列 monad 规则是将产生序列的两个函数组合在一起,将外部函数应用于内部函数产生的每个元素,然后将所有结果序列连接在一起".monad 的基本语义在 Bind/SelectMany 方法中捕获;这是告诉您 monad 真正含义的方法.

The sequence monad rule is "to combine two functions that produce sequences together, apply the outer function to every element produced by the inner function, and then concatenate all the resulting sequences together". The fundamental semantics of the monads are captured in the Bind/SelectMany methods; this is the method that tells you what the monad really means.

我们可以做得更好.假设您有一个整数序列,以及一个接受整数并生成字符串序列的方法.我们可以概括绑定操作以允许组合接受和返回不同放大类型的函数,只要一个的输入与另一个的输出匹配:

We can do even better. Suppose you have a sequences of ints, and a method that takes ints and results in sequences of strings. We could generalize the binding operation to allow composition of functions that take and return different amplified types, so long as the inputs of one match the outputs of the other:

static IEnumerable<U> SelectMany<T,U>(IEnumerable<T> seq, Func<T, IEnumerable<U>> func)
{
    foreach(T item in seq)
        foreach(U result in func(item))
            yield return result;            
}

所以现在我们可以说将这串单独的整数放大成一个整数序列.将这个特定的整数转换成一堆字符串,放大成一个字符串序列.现在把这两个操作放在一起:把这串整数放大成所有字符串序列的串联."Monads 允许你组合你的放大.

So now we can say "amplify this bunch of individual integers into a sequence of integers. Transform this particular integer into a bunch of strings, amplified to a sequence of strings. Now put both operations together: amplify this bunch of integers into the concatenation of all the sequences of strings." Monads allow you to compose your amplifications.

它解决了什么问题,最常用的地方是什么?

What problem does it solve and what are the most common places it's used?

这更像是在问单例模式解决了什么问题?",但我会试一试.

That's rather like asking "what problems does the singleton pattern solve?", but I'll give it a shot.

Monads 通常用于解决以下问题:

Monads are typically used to solve problems like:

  • 我需要为这种类型创建新功能,并且仍然在这种类型上结合旧功能以使用新功能.
  • 我需要捕获一系列对类型的操作,并将这些操作表示为可组合对象,构建越来越大的组合,直到我拥有正确的一系列操作,然后我需要开始从事物中获取结果
  • 我需要用一种讨厌副作用的语言干净利落地表示副作用

C# 在其设计中使用 monad.正如已经提到的,可空模式与maybe monad"非常相似.LINQ 完全由 monad 构建; 方法是代码 代码操作组合的语义工作是什么.(Erik Meijer 喜欢指出,每个 LINQ 函数实际上都可以通过 SelectMany;其他一切只是为了方便.)

C# uses monads in its design. As already mentioned, the nullable pattern is highly akin to the "maybe monad". LINQ is entirely built out of monads; the SelectMany method is what does the semantic work of composition of operations. (Erik Meijer is fond of pointing out that every LINQ function could actually be implemented by SelectMany; everything else is just a convenience.)

为了澄清我正在寻找的那种理解,假设您正在将具有 monad 的 FP 应用程序转换为 OOP 应用程序.您将如何将 monad 的职责移植到 OOP 应用中?

To clarify the kind of understanding I was looking for, let's say you were converting an FP application that had monads into an OOP application. What would you do to port the responsibilities of the monads into the OOP app?

大多数 OOP 语言没有足够丰富的类型系统来直接表示 monad 模式本身;您需要一个类型系统来支持比泛型类型更高的类型.所以我不会尝试这样做.相反,我会实现表示每个 monad 的泛型类型,并实现表示您需要的三个操作的方法:将值转换为放大值,(可能)将放大值转换为值,以及将未放大值上的函数转换为放大值的函数.

Most OOP languages do not have a rich enough type system to represent the monad pattern itself directly; you need a type system that supports types that are higher types than generic types. So I wouldn't try to do that. Rather, I would implement generic types that represent each monad, and implement methods that represent the three operations you need: turning a value into an amplified value, (maybe) turning an amplified value into a value, and transforming a function on unamplified values into a function on amplified values.

一个很好的起点是我们如何在 C# 中实现 LINQ.研究 方法;它是理解序列 monad 在 C# 中如何工作的关键.这是一个非常简单的方法,但是非常强大!

方法;它是理解序列 monad 在 C# 中如何工作的关键.这是一个非常简单的方法,但是非常强大!

A good place to start is how we implemented LINQ in C#. Study the SelectMany method; it is the key to understanding how the sequence monad works in C#. It is a very simple method, but very powerful!

建议,进一步阅读:

    方法;它是理解序列 monad 在 C# 中如何工作的关键.这是一个非常简单的方法,但是非常强大!
  1. 方法;它是理解序列 monad 在 C# 中如何工作的关键.这是一个非常简单的方法,但是非常强大!要对 C# 中的 monad 进行更深入和理论上合理的解释,我强烈推荐我的 (Eric Lippert's) 同事 Wes Dyer 关于这个主题的文章.当 monad 最终点击"我时,这篇文章向我解释了它们.
  1. For a more in-depth and theoretically sound explanation of monads in C#, I highly recommend my (Eric Lippert's) colleague Wes Dyer's article on the subject. This article is what explained monads to me when they finally "clicked" for me.
    • The Marvels of Monads
  • You Could Have Invented Monads! (And Maybe You Already Have.) by Dan Piponi
  • Translation from Haskell to JavaScript of selected portions of the best introduction to monads I’ve ever read by James Coglan

这篇关于Monad 是简单的英语吗?(对于没有FP背景的OOP程序员)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,WP2

admin_action_{$_REQUEST[‘action’]}

do_action( "admin_action_{$_REQUEST[‘action’]}" )动作钩子::在发送“Action”请求变量时激发。Action Hook: Fires when an ‘action’ request variable is sent.目录锚点:#说明#源码说明(Description)钩子名称的动态部分$_REQUEST['action']引用从GET或POST请求派生的操作。源码(Source)更新版本源码位置使用被使用2.6.0 wp-admin/admin.php:...

日期:2020-09-02 17:44:16 浏览:1159

admin_footer-{$GLOBALS[‘hook_suffix’]}

do_action( "admin_footer-{$GLOBALS[‘hook_suffix’]}", string $hook_suffix )操作挂钩:在默认页脚脚本之后打印脚本或数据。Action Hook: Print scripts or data after the default footer scripts.目录锚点:#说明#参数#源码说明(Description)钩子名的动态部分,$GLOBALS['hook_suffix']引用当前页的全局钩子后缀。参数(Parameters)参数类...

日期:2020-09-02 17:44:20 浏览:1060

customize_save_{$this->id_data[‘base’]}

do_action( "customize_save_{$this-&gt;id_data[‘base’]}", WP_Customize_Setting $this )动作钩子::在调用WP_Customize_Setting::save()方法时激发。Action Hook: Fires when the WP_Customize_Setting::save() method is called.目录锚点:#说明#参数#源码说明(Description)钩子名称的动态部分,$this->id_data...

日期:2020-08-15 15:47:24 浏览:800

customize_value_{$this->id_data[‘base’]}

apply_filters( "customize_value_{$this-&gt;id_data[‘base’]}", mixed $default )过滤器::过滤未作为主题模式或选项处理的自定义设置值。Filter Hook: Filter a Customize setting value not handled as a theme_mod or option.目录锚点:#说明#参数#源码说明(Description)钩子名称的动态部分,$this->id_date['base'],指的是设置...

日期:2020-08-15 15:47:24 浏览:887

get_comment_author_url

过滤钩子:过滤评论作者的URL。Filter Hook: Filters the comment author’s URL.目录锚点:#源码源码(Source)更新版本源码位置使用被使用 wp-includes/comment-template.php:32610...

日期:2020-08-10 23:06:14 浏览:925

network_admin_edit_{$_GET[‘action’]}

do_action( "network_admin_edit_{$_GET[‘action’]}" )操作挂钩:启动请求的处理程序操作。Action Hook: Fires the requested handler action.目录锚点:#说明#源码说明(Description)钩子名称的动态部分$u GET['action']引用请求的操作的名称。源码(Source)更新版本源码位置使用被使用3.1.0 wp-admin/network/edit.php:3600...

日期:2020-08-02 09:56:09 浏览:873

network_sites_updated_message_{$_GET[‘updated’]}

apply_filters( "network_sites_updated_message_{$_GET[‘updated’]}", string $msg )筛选器挂钩:在网络管理中筛选特定的非默认站点更新消息。Filter Hook: Filters a specific, non-default site-updated message in the Network admin.目录锚点:#说明#参数#源码说明(Description)钩子名称的动态部分$_GET['updated']引用了非默认的...

日期:2020-08-02 09:56:03 浏览:855

pre_wp_is_site_initialized

过滤器::过滤在访问数据库之前是否初始化站点的检查。Filter Hook: Filters the check for whether a site is initialized before the database is accessed.目录锚点:#源码源码(Source)更新版本源码位置使用被使用 wp-includes/ms-site.php:93910...

日期:2020-07-29 10:15:38 浏览:825

WordPress 的SEO 教学:如何在网站中加入关键字(Meta Keywords)与Meta 描述(Meta Description)?

你想在WordPress 中添加关键字和meta 描述吗?关键字和meta 描述使你能够提高网站的SEO。在本文中,我们将向你展示如何在WordPress 中正确添加关键字和meta 描述。为什么要在WordPress 中添加关键字和Meta 描述?关键字和说明让搜寻引擎更了解您的帖子和页面的内容。关键词是人们寻找您发布的内容时,可能会搜索的重要词语或片语。而Meta Description则是对你的页面和文章的简要描述。如果你想要了解更多关于中继标签的资讯,可以参考Google的说明。Meta 关键字和描...

日期:2020-10-03 21:18:25 浏览:1692

谷歌的SEO是什么

SEO (Search Engine Optimization)中文是搜寻引擎最佳化,意思近于「关键字自然排序」、「网站排名优化」。简言之,SEO是以搜索引擎(如Google、Bing)为曝光媒体的行销手法。例如搜寻「wordpress教学」,会看到本站的「WordPress教学:12个课程…」排行Google第一:关键字:wordpress教学、wordpress课程…若搜寻「网站架设」,则会看到另一个网页排名第1:关键字:网站架设、架站…以上两个网页,每月从搜寻引擎导入自然流量,达2万4千:每月「有机搜...

日期:2020-10-30 17:23:57 浏览:1298