したがって、この出版物では、次の質問に対する答えは見つかりません。
1.モナドとは何ですか?
2.モナドの使用場所と方法
3.モナドが存在しないよりも優れているのはなぜですか?
プログラミングでは、このような現象があります-「デザインパターン」。 公式には、これは「典型的な問題」を解決する際に従うべき一連のベストプラクティスです。 非公式には、一般的な問題を解決するための組み込みツールを持たない言語のための松葉杖のセットにすぎません。
そのようなデザインパターンがあります- 通訳 。 まず第一に、それはあなたが好きなプログラミング言語の上にある種の仮想マシンを作ることができるので、驚くべきことです:
1.仮想マシンが理解できる言語でプログラムを記述できます。
2.仮想マシンが各命令をどのように解釈するかを記述するために、すべての詳細で
親切な読者が言及されたパターンに最低限精通している場合にのみ、以下に書かれているすべてが意味をなします。
比較的標準的な例:
function add(x) { return { op: "add", x: x }; } function div(x) { return { op: "div", x: x }; } function run(value, statements) { for(var i = 0; i < statements.length; ++i) { var statement = statements[i]; var op = statement.op; var x = statement.x; if(op === "add") { value += x; } else if(op === "div") { value /= x; } else { throw new Error("Unknown operation " + op); } } return value; } var program = [ add(10), div(3) ]; var result = run(0, program); console.log(result); // 3.3333...
GoFの愛好家は、「これは通訳ではなく、コマンドである」と主張することができます。 彼らにとっては、それをコマンドとしましょう。 この記事の文脈では、これはあまり重要ではありません。
この例では、まず、「10を加算」と「3で除算」という2つの命令で構成されるプログラムがあります。 それが何を意味するにせよ。 第二に、プログラムを見ながら何か
add()の console.log()への翻訳は私たちにとって面白くないことに同意します。 コンピューティングは面白いです。 したがって、不必要な柔軟性を放棄することでコードを少し単純化します。
function add(x) { // add(2)(3) === 5 return function(a) { return a + x; }; } function div(x) { // div(10)(5) === 2 return function(a) { return a / x; }; } function run(value, statements) { for(var i = 0; i < statements.length; ++i) { var statement = statements[i]; value = statement(value); } return value; } var program = [ add(10), div(3) ]; var result = run(program); console.log(0, result); // 3.3333...
ここに滞在する価値があります。 プログラムを個別に記述し、「プログラムを実行する方法」を個別に記述できるツールがあります。 パフォーマンスの結果に対する希望に応じて、請負業者の実装は非常に異なる場合があります。
たとえば、 NaN 、 nullまたはundefinedが計算のどこかに現れるとすぐに計算が停止し、結果がnullになるようにします 。
... function run(value, statements) { if(!value) { return null; } for(var i = 0; i < statements.length; ++i) { var statement = statements[i]; value = statement(value); if(!value) { return null; } } return value; } console.log(run(undefined, [add(1)])); // null console.log(run(1, [add(undefined)])); // null
いいね しかし、異なる初期値のコレクションに対して同じプログラムを実行したい場合はどうでしょうか? また質問ではありません:
... function run(values, statements) { return values.map(function(value) { for(var i = 0; i < statements.length; ++i) { var statement = statements[i]; value = statement(value); } return value; }); } var program = [ add(10), div(3) ]; console.log(run([0, 1, 2], program)); // [3.333..., 3.666..., 4]
ここに再び滞在する価値があります。 プログラムを説明するのに同じ表現を使用しますが、アーティストによって非常に異なる結果が得られます。 それでは、例をもう一度書き直してみましょう。 今回は、まず柔軟性を少し削除します。式は最初から最後まで厳密に実行されるようになり、次に、 run()内のループを取り除きます。 結果を単語コンテキストと呼びます(だれも推測しないように):
... function Context(value) { this.value = value; } Context.prototype.run = function(f) { var result = f(this.value); return new Context(result); }; var result = new Context(0) .run(add(10)) .run(div(3)) .value; console.log(result); // 3.3333...
実装は以前のオプションとは非常に異なりますが、ほぼ同じです。 ムンダダという用語を導入することが提案されています(英語のムーンアド -「月の広告」から)。 Hello Identity moonad:
... function IdentityMoonad(value) { this.value = value; } IdentityMoonad.prototype.bbind = function(f) { var result = f(this.value); return new IdentityMoonad(result); }; var result = new IdentityMoonad(0) .bbind(add(10)) .bbind(div(3)) .value; console.log(result); // 3.3333...
このことは、 Identityモナドに多少似ています。
次に、 NaNと戦ったアーティストのバージョンを思い出して、実装の新しいアプローチを使用して書き直そうとします。
function MaybeMoonad(value) { this.value = value; } MaybeMoonad.prototype.bbind = function(f) { if(!this.value) { return this; } var result = f(this.value); return new MaybeMoonad(result); }; var result = new MaybeMoonad(0) .bbind(add(10)) .bbind(add(undefined)) .bbind(div(3)) .value; console.log(result); // null
さらに馴染みのある例:
var person = { // address: { // city: { // name: "New York" // } // } }; console.log(person.address.city.name); // console.log(new MaybeMoonad(person) .bbind(function(person) { return person.address; }) .bbind(function(address) { return address.city; }) .bbind(function(city) { return city.name; }) .bbind(function(cityName) { return cityName; }) .value); // , null
遠くからは、 多分モナドのように見えるかもしれません。 親切な読者は、 リストモナドに似た何かを独自に実装するように招待されています。
基本的なファイルスキルでは、 f()呼び出しが非同期になるようにIdentityMoonadを変更することは意味がありません。 結果はPromise moonad ( qに似たもの)です。
さて、最新の例をよく見ると、多かれ少なかれmunadaの正式な定義を試みることができます。 Munadaは2つの操作を持つものです。
1. return-通常の値を取得し、それをムナディックコンテキストに入れて、このコンテキストを返します。 これは単なるコンストラクター呼び出しです。
2. bind-通常値を返す関数を通常値から取得し、それをムナディックコンテキストのコンテキストで実行し、モナドコンテキストを返します。 これは、「bbind()」の呼び出しです。