2016-08-27 29 views
5

JavaScriptでの関数型プログラミングに精通しています。私はちょうどreadそのポインタファンクタは:尖ったファンクタの使い方

それに任意の単一の値を置く関数を持つオブジェクトです。

ES2015は、Array.ofを追加して、配列を尖ったファンクタにします。

私の質問は「単一価値」を意味していますか?

与えられた次元(幅、高さ)のグリッドを1次元配列として保持し、その上での変換を可能にするFunctor/Container(例えばhttps://drboolean.gitbooks.io/mostly-adequate-guide/content/ch8.htmlのような)を作りたいと思います。普通のオブジェクトとして、私は{ width: 2, height: 2, list: [1, 2, 3, 4] }という名前で保存しますが、それをファンクタに入れたいので、正しく行う方法がわかりません。

私はそれが単一の値格納するために、次のように尖ったファンクタを使用するように完全に罰金だということを知っている:

Container.of(47) 

をしかし、それはオブジェクトを想定した値は、「単一の値」であるとして、オブジェクトを使用しても大丈夫です。

Grid.of({ width: 2, height: 2, list: [1, 2, 3, 4] }) 

、あるいはこのような:

Grid.of(2, 2, [1, 2, 3, 4]) 
+0

「Foo.of」とは何ですか?あなたはArray.ofを意味しましたか?私はEs2015の時点で、Arrayと* TypedArray *には 'of'があると思ったのです –

+0

あなたの期待する出力は?あなたのポイントをあまり得ていない。 – Leo

+0

あなたの入力データの例と期待される結果の配列内容を挙げてください。あなたが私に 'Foo'と混同させてしまいました。 –

答えて

5

https://github.com/hemanth/functional-programming-jargonの説明はあいにくあまり正確ではありません。

尖ったファンクタ本当にあらゆるタイプaに対して定義された関数of、及びタイプF aの値of(x)にタイプaの値xを送信するとともにファンクタFあります。 Hindley-Milner signatureでは、それは次のようになります。例えば

of :: a -> F a 

、アレイファンクタは、任意のタイプaのすべての値xのために定義され、of = x => [x]と指摘しています。

さらに、機能of(またはより正確には、機能ofのコレクションは、あなたは、各タイプaに1つを持っているとして)Fにアイデンティティ数子から自然形質転換する必要があります。これは、関数の値のofは、同じ機能の上にマッピングされた引数のofに等しいことを意味します

例えば
of(f(x)) === of(x).map(f) 

、アレイの例では、あなたが

[f(x)] === [x].map(f), 

を持っているので、x => [x]は確かに自然形質転換です。

しかし、あなたはまた、ファンクタのmapが同じであっても、別の尖ったファンクタである

of = x => [x, x] 
[f(x), f(x)] === [x, x].map(f) 

を取ることができます。 (どちらの場合でも、値がof(x)の非常に特殊な配列しか得られません)。

ただし、

of = x => [x, 0] 
[f(x), 0] !== [x, 0].map(f) 

var grid = Grid.of({ width: 2, height: 2, list: [1, 2, 3, 4] }) 

完全に大丈夫ですとGridにラップ渡されたあなたのオブジェクトを返します。 gridと通常の関数fをプレーンオブジェクトからプレーンオブジェクトにマップすると、自然変換法のためにfを適用し、Gridにラップするのと同じ結果になります。この方法では、Grid.of({width: 2})のような他の値でGrid.ofを呼び出すこともできます。Grid.of(2)です。または、Grid.ofが定義されているタイプを制限することができます。値は、許可するタイプの値でなければなりません。


この1つは少しトリッキーです:

Grid.of(2, 2, [1, 2, 3, 4]) 

これは、いくつかの引数にGrid.ofを適用します。Grid.ofは1つの引数だけの関数であるため、結果はGrid.of(2)になります。あなたが本当にすべての値を供給したい場合は、おそらくあなたが内部の配列にそれらを事前にラップしてからGrid.ofを適用することによって、複数の引数にGrid.ofを拡張することができ、また

Grid.of([2, 2, [1, 2, 3, 4]]) 

を書きたいです。それは本当にあなたが何をしているかによって異なります。

実際の使用例については、たとえばhereここで、「退屈な」タスクは、平方の値からTask.ofによって定義されます。一方、hereは、Task.ofで取得できない関数をラッピングする、より興味深いタスクです。しかし重要なことは、両方のタスクが両方の例に示されているように同じ統一インターフェースで使用できることです。

また、これらの例ではアプリケーションファンクタは使用されていないので、依然として適用可能ではない尖ったファンクタの使用があります。

4

オブジェクトを「単一の値」と仮定してobjectを値として使用しても問題ありません:

はい。 ofは、のいずれかの値をとし、コンテナの中に入れます。オブジェクトは確かにそのような単一の値です。

Grid.of(2, 2, [1, 2, 3, 4])

ofは、単一のパラメータを取ることになっています。ファンクタ内に複数の値を入れたい場合は、それを前もって他の構造体の中に入れて、その構造体をファンクタの中に入れたり、ファンクタ(of)以外のものでファンクタを構築してください。

Grid.of({ width: 2, height: 2, list: [1, 2, 3, 4] })

あなたはそれが入力を返すことが予想される場合はありません、それは動作しません。 ofは入力をそのまま受け取り、構造体をその周囲にラップする必要があります。あなたのグリッドの場合には、それは最も確かに次のようになります。

// Grid<A> 
class Grid { 
    // Int -> Int -> [A] -> Grid<A> 
    constructor(w, h, vals) { 
     assert(Number.isInteger(w) && Number.isInteger(h)); 
     this.width = w; 
     this.height = h; 
     const list = Array.from(vals); 
     assert(list.length == w * h); 
     this.list = list; 
    } 
    // Grid<A> -> (A -> B) -> Grid<B> 
    map(f) { 
     return new Grid(this.width, this.height, this.list.map(f)); 
    } 
    // A -> Grid<A> 
    static of(x) { 
     return new Grid(1, 1, [x]); 
    } 
} 

したがって、上記の呼び出しは4つの数字のグリッド、オブジェクトのGridをない作成します。ファンクタのインスタンスを構築する唯一の方法はofではないことに注意してください。これは、単一の要素からインスタンスを構築する唯一の方法です。

ofは、アプリケーションの一部として最も重要であることに注意してください。通常のFunctorではそれほど面白くありません。Btw、関数型プログラミングの概念に興味があるなら、GridをMonoid、Traversable、Monadにすることもできるはずです - https://github.com/fantasyland/fantasy-landを参照してください。

+0

だから私は 'of'は必要ないと思われ、必要なのはオブジェクトを作成するためのまともな方法です。私は授業を避けていました。彼らは私には機能していないようで、チュートリアルでは見たことがありませんでした。今、私はこれらの2つの世界がひとつになっているのを見ています。 – jesper

+0

コンストラクタを純粋にするには?私はOOPの世界で何らかの例外をスローしなければならないとイメージしていますが、純粋に機能的にしたいのであればどうしますか?私は、左、右のどちらかに慣れ親しんでいますが、ここでそれをどのように適用するかはわかりません。私が持っている1つの解決策は、提供された値が有効なグリッドを指定しているかどうかをチェックし、Gridオブジェクトまたはエラーを返す関数にGridオブジェクトの作成を委任することです。これは正しいアプローチですか? – jesper

+1

@ jesper:はい、 'of'は必須ではなく、インスタンスを作成する唯一の方法ではありません。あなたのデータ型がファンタジーランド仕様に準拠していれば、Ramdaのような多くの機能ライブラリを使って作業することができます。もちろん、クラスは機能的なアプローチと決して矛盾しません。データを保持するためには、常に「レコード」や「オブジェクト」を実行する方法が必要です。ファクトリ関数と静的関数で同じことをすることができますが、ここでは 'class'構文を選択しました。 – Bergi

関連する問題