JavaScriptでの関数型プログラミングの基礎となる基本概念のいくつか/多く/ほとんどを学んだと思います。ただし、私は関数コード、特に自分で作成したコードを明確に読み取ることができず、誰かが役立つヒント、ヒント、ベストプラクティス、用語などを教えてくれるかどうか疑問に思っています。
以下のコードを見てください。私はこのコードを書きました。これは、say {a:1, b:2, c:3, d:3}
との間の2つのオブジェクト間のパーセント類似性を割り当てることを目的としてい{a:1, b:1, e:2, f:2, g:3, h:5}
ます。Stack Overflowでこの質問に答えてコードを作成しました。ポスターがどの程度の類似性について尋ねているのか正確にはわからなかったため、4つの異なる種類を用意しました。
- 2番目にある1番目のオブジェクトのキーの割合、
- 重複を含む、2番目にある1番目のオブジェクトの値のパーセント
- 重複が許可されていない、2番目に見つかった1番目のオブジェクトの値の割合、および
- 2番目のオブジェクトにある1番目のオブジェクトの{key:value}ペアの割合。
私は合理的に命令型のコードから始めましたが、これは関数型プログラミングに適した問題であることをすぐに理解しました。特に、私が比較しようとしている機能のタイプ(例えば、キーや値など)を定義する上記の4つの戦略のそれぞれについて関数または3つを抽出できれば、残りのコードを繰り返し可能な単位に減らす(言葉の遊びを許す)ことができます。あなたはそれを乾いた状態に保ちます。そこで関数型プログラミングに切り替えました。結果にはかなり誇りに思っており、それは適度にエレガントだと思います。
ただし、コードを自分で作成し、構築中にコードのすべての部分を理解したとしても、今振り返ると、特定の半行の読み方と読み方の両方に少し戸惑い続けています。コードの特定の半行が実際に行っていることを「グロッ」と言います。私は、すぐにスパゲッティの混乱に分解するさまざまな部分を接続するために精神的な矢を作ることに気づきました。
だから、誰かが私に、コードのより複雑なビットのいくつかを、簡潔で、私が読んでいるものの私の理解に貢献する方法で「読む」方法を教えてもらえますか?私を最も引き付ける部分は、複数の太い矢印が連続している部分、および/または複数の括弧が連続している部分だと思います。繰り返しになりますが、最終的にはロジックを理解することができますが、関数型JavaScriptプログラミングの行をすばやく明確かつ直接「取り込む」ためのより良い方法があります(私はそう思います)。
以下のコード行、または他の例を自由に使用してください。ただし、私からの最初の提案が必要な場合は、以下にいくつか示します。かなりシンプルなものから始めます。コードの終わり近くから、これがパラメーターとして関数に渡されますobj => key => obj[key]
。それをどのように読んで理解しますか?より長い例は、最初から近い1つの完全な関数ですconst getXs = (obj, getX) => Object.keys(obj).map(key => getX(obj)(key));
。最後のmap
部分は特に私を捕まえます。
ノート、この時点で時間に私はしてくださいないなどハスケルやシンボリック抽象記法やカリー化の基礎への参照を探している私は何をしています探しているコードの行を見ながら、私は口を静かにできることを、英語の文章です。具体的にそれについて具体的に言及している参考文献があればすばらしいですが、私はいくつかの基本的な教科書を読みに行くべきだと言う答えも探していません。私はそれを実行し、私は(少なくともかなりの量の)ロジックを取得しました。また、私は完全な答えは必要ありません(そのような試みは歓迎されますが)。そうでなければ面倒なコードの単一の特定の行を読むためのエレガントな方法を提供する短い答えでさえいただければ幸いです。
この質問の一部は次のとおりだと思います:関数コードを左から右へ、上から下へ直線的に読み取ることはできますか?それとも、明らかに線形ではないコードのページにスパゲッティのような配線の精神的な画像を作成することを強いられていますか?それを行う必要がある場合でも、コードを読み取る必要があるので、線形テキストを取得してスパゲッティを配線するにはどうすればよいでしょうか。
任意のヒントをいただければ幸いです。
const obj1 = { a:1, b:2, c:3, d:3 };
const obj2 = { a:1, b:1, e:2, f:2, g:3, h:5 };
// x or X is key or value or key/value pair
const getXs = (obj, getX) =>
Object.keys(obj).map(key => getX(obj)(key));
const getPctSameXs = (getX, filter = vals => vals) =>
(objA, objB) =>
filter(getXs(objB, getX))
.reduce(
(numSame, x) =>
getXs(objA, getX).indexOf(x) > -1 ? numSame + 1 : numSame,
0
) / Object.keys(objA).length * 100;
const pctSameKeys = getPctSameXs(obj => key => key);
const pctSameValsDups = getPctSameXs(obj => key => obj[key]);
const pctSameValsNoDups = getPctSameXs(obj => key => obj[key], vals => [...new Set(vals)]);
const pctSameProps = getPctSameXs(obj => key => JSON.stringify( {[key]: obj[key]} ));
console.log('obj1:', JSON.stringify(obj1));
console.log('obj2:', JSON.stringify(obj2));
console.log('% same keys: ', pctSameKeys (obj1, obj2));
console.log('% same values, incl duplicates:', pctSameValsDups (obj1, obj2));
console.log('% same values, no duplicates: ', pctSameValsNoDups(obj1, obj2));
console.log('% same properties (k/v pairs): ', pctSameProps (obj1, obj2));
// output:
// obj1: {"a":1,"b":2,"c":3,"d":3}
// obj2: {"a":1,"b":1,"e":2,"f":2,"g":3,"h":5}
// % same keys: 50
// % same values, incl duplicates: 125
// % same values, no duplicates: 75
// % same properties (k/v pairs): 25