合理的に純粋な機能プログラミングの紹介
Feb 18, 2025 pm 12:58 PM
キーテイクアウト
- 純粋な機能は、副作用を引き起こすことなく同じ入力に対して同じ出力を返すため、機能的なプログラミングに不可欠です。 機能的プログラミングにより、プロセスをよりシンプルで不変の機能に分解することにより、プログラムの複雑さが低下し、バグを最小限に抑え、コードの読みやすさの向上に役立ちます。 機能プログラミングの過剰抽出は、コードの複雑さを減らす一方で、理解して維持するのが難しく、バランスの重要性を強調するコードにつながる可能性があります。
- 「map」、 `reduce」、` filter`、 `compose`などの重要なJavaScript関数は、機能的なプログラミングパラダイムを採用し、より簡潔で宣言的なコードの作成を促進します。 テストは、孤立した性質により、テスト条件のセットアップと予想される結果のセットアップが容易になるため、より簡単になります。
- 機能プログラミングは理論的な概念であるだけでなく、非同期操作やUIの更新の処理などの実際のシナリオに適用され、最新のWeb開発におけるその関連性を示しています。 この記事は、Panayiotis«Pvgr»Velisarakos、Jezen Thomas、Florian Rapplによって査読されました。 SetePointコンテンツを最高にしてくれたSitePointのすべてのピアレビュアーに感謝します!プログラムを学ぶとき、最初に手続き上のプログラミングを紹介します。これは、マシンをコマンドのシーケンシャルリストに供給することにより、マシンを制御する場所です。 変数、割り当て、関数、オブジェクトなどのいくつかの言語の基礎を理解した後、あなたがそれを設定したことを達成するプログラムを一緒に丸み合わせます - そして、あなたは絶対的な魔法使いのように感じます。
- より良い プログラマーになるプロセスは、あなたが書いているプログラムを制御するより大きな能力を獲得し、
- 正しい と
機能プログラミングは、プログラムを最も単純な形式に縮小することにより、プログラムの複雑さを低下させる方法を提供します。これは、純粋な数学的関数のように振る舞う機能です。 機能プログラミングの原則を学ぶことは、スキルセットに最適な追加であり、バグが少ないシンプルなプログラムを作成するのに役立ちます。
機能的プログラミングの重要な概念は、純粋な機能、不変の値、構成、副作用です。純粋な関数
純粋な関数とは、同じ入力が与えられた場合、常に同じ出力を返し、観察可能な副作用を持たない関数です。
純粋この関数は
<span>// pure </span><span>function add(a<span>, b</span>) { </span> <span>return a + b; </span><span>} </span>
常に同じ入力に対して同じ出力値を返します。 この関数は、関数の外側の外部可変状態に依存しているため、不純物です。 この変数を関数内で移動すると、それは純粋になり、私たちの関数が毎年を正しくチェックすることを確信できます
。<span>// impure </span><span>var minimum = 21; </span><span>var checkAge = function(age) { </span> <span>return age >= minimum; // if minimum is changed we're cactus </span><span>}; </span>
純粋な関数には副作用がありません。ここに留意すべき重要なものがいくつかあります:
関数の外側のシステム状態にアクセス
引数として渡された変異オブジェクト<span>// pure </span><span>var checkAge = function(age) { </span> <span>var minimum = 21; </span> <span>return age >= minimum; </span><span>}; </span>
http呼び出しを作成します ユーザー入力の取得
- dom
- のクエリ
- 制御された突然変異
- アンダーリングオブジェクトを変更する配列とオブジェクトのミューテーターメソッドに注意する必要があります。この例は、配列のスプライスとスライス方法の違いです。
- 機能に渡されたオブジェクトの変異を避けた場合、プログラムが推論しやすくなるようになると、私たちの関数が私たちの下から物事を切り替えないことを合理的に期待できます。
- 純粋な関数の利点
彼らの唯一の責任は入力 - >出力をマップすることであるため、より簡単にテストしやすい
同じ入力が常に同じ出力を生成するため、
結果はキャッシュ可能です<span>// impure, splice mutates the array </span><span>var firstThree = function(arr) { </span> <span>return arr.splice(0,3); // arr may never be the same again </span><span>}; </span> <span>// pure, slice returns a new array </span><span>var firstThree = function(arr) { </span> <span>return arr.slice(0,3); </span><span>}; </span>
自己文書化
副作用を心配する必要がないので、操作しやすい<span>let items = ['a','b','c']; </span><span>let newItems = pure(items); </span><span>// I expect items to be ['a','b','c'] </span>
純粋な関数の結果はキャッシュ可能であるため、機能が初めて呼び出されたときにのみ実行されるため、それらをメモ化できます。 たとえば、大きなインデックスを検索する結果をメモ化すると、再実行の大きなパフォーマンスの改善が得られます。
不当に純粋な機能的プログラミング
- プログラムを純粋な機能に減らすと、プログラムの複雑さを大幅に減らすことができます。ただし、機能的なプログラムは、機能的な抽象化をあまりにも押し上げている場合、レインマンの支援を理解するために最終的に必要とする可能性があります。
- 上のコードを消化するのに少し時間がかかります。
-
機能的なプログラミングの背景がない限り、これらの抽象化(カレー、作曲と小道具の過度の使用)は、実行の流れと同様に、従うのが非常に困難です。 以下のコードは理解しやすく、変更する方が簡単で、上記の純粋に機能的なアプローチよりもプログラムをはるかに明確に説明しており、コードが少ない。
- アプリ関数には、タグの文字列
- が取得されます flickr
- からjsonを取得します URLSを応答
- に引き出します
- を構築します ドキュメントに挿入します
ノードの配列
<span>// pure </span><span>function add(a<span>, b</span>) { </span> <span>return a + b; </span><span>} </span>
ログイン後にコピーログイン後にコピーログイン後にコピーログイン後にコピー注:フェッチと約束は今後の基準であるため、今日使用するにはポリフィルが必要です。
ajax要求とDOM操作は純粋になることはありませんが、残りの部分から純粋な機能を作成して、JSONの一連の画像へのマッピングを行うことができます。<span>// impure </span><span>var minimum = 21; </span><span>var checkAge = function(age) { </span> <span>return age >= minimum; // if minimum is changed we're cactus </span><span>}; </span>
ログイン後にコピーログイン後にコピーログイン後にコピーログイン後にコピー私たちの関数は今、2つのことをしているだけです:
<span>// pure </span><span>var checkAge = function(age) { </span> <span>var minimum = 21; </span> <span>return age >= minimum; </span><span>}; </span>
ログイン後にコピーログイン後にコピーログイン後にコピーログイン後にコピーマッピングURLS->画像
-
これを行う「機能的な」方法は、これらの2つのタスクの個別の関数を作成することであり、Composeを使用して、一方の関数の応答を他の関数に渡すことができます。
-
これが行われていることです。URLの応答を画像関数に渡します。
composeは、関数のリストの構成である関数を返し、それぞれが続く関数の返品値を消費します。 プログラムを純粋な機能に減らすことにより、将来それらを再利用する能力が高まり、テストがはるかに簡単で、自己文書化されています。 欠点は、(最初の例のように)過度に使用すると、これらの機能的な抽象化により、
より複雑なになる可能性があるということです。 コードをリファクタリングするときに尋ねる最も重要な質問はこれです:<span>// impure, splice mutates the array </span><span>var firstThree = function(arr) { </span> <span>return arr.splice(0,3); // arr may never be the same again </span><span>}; </span> <span>// pure, slice returns a new array </span><span>var firstThree = function(arr) { </span> <span>return arr.slice(0,3); </span><span>}; </span>
ログイン後にコピーログイン後にコピーログイン後にコピーログイン後にコピーコードは読みやすく理解しやすいですか?
<span>let items = ['a','b','c']; </span><span>let newItems = pure(items); </span><span>// I expect items to be ['a','b','c'] </span>
ログイン後にコピーログイン後にコピーログイン後にコピー基本的な機能のレパートリーで武装したプログラマー、さらに重要なことには、それらの使用方法に関する知識は、ゼロから始まる人よりもはるかに効果的です。 - Eloquent JavaScript、Marijn Haverbeke
ここに、すべてのJavaScript開発者が学習してマスターする必要がある重要な機能のリストがあります。また、JavaScriptのスキルを磨いて、これらの各機能をゼロから書くのに最適な方法でもあります。
配列- foreach
- Map
- フィルター
- 減少
- debounce
- を作成します partial
- curry
を減らします<span>// pure </span><span>function add(a<span>, b</span>) { </span> <span>return a + b; </span><span>} </span>
ログイン後にコピーログイン後にコピーログイン後にコピーログイン後にコピーこれは明白で些細なことに聞こえるかもしれませんが、私はまだ自分の外に多くの状態にアクセスして変更する機能を書きます。これにより、テストが難しくなり、エラーが発生しやすくなります。
反復するためにforeachのような読みやすい言語抽象化を使用します
<span>// impure </span><span>var minimum = 21; </span><span>var checkAge = function(age) { </span> <span>return age >= minimum; // if minimum is changed we're cactus </span><span>}; </span>
ログイン後にコピーログイン後にコピーログイン後にコピーログイン後にコピーマップのような高レベルの抽象化を使用して、コードの量を減らす
<span>// pure </span><span>var checkAge = function(age) { </span> <span>var minimum = 21; </span> <span>return age >= minimum; </span><span>}; </span>
ログイン後にコピーログイン後にコピーログイン後にコピーログイン後にコピー機能を最も単純なフォームに低下させます
<span>// impure, splice mutates the array </span><span>var firstThree = function(arr) { </span> <span>return arr.splice(0,3); // arr may never be the same again </span><span>}; </span> <span>// pure, slice returns a new array </span><span>var firstThree = function(arr) { </span> <span>return arr.slice(0,3); </span><span>}; </span>
ログイン後にコピーログイン後にコピーログイン後にコピーログイン後にコピー動作が停止するまでコードを削除します
このような単純なタスクのために関数はまったく必要ありません。言語は、逐語的に書き出すのに十分な抽象化を提供します。<span>let items = ['a','b','c']; </span><span>let newItems = pure(items); </span><span>// I expect items to be ['a','b','c'] </span>
ログイン後にコピーログイン後にコピーログイン後にコピーターミナルを起動してテキストエディターに準備を整えて準備ができています。Mochaをテストランナーとして使用し、ES6コードをコンパイルするためにBabelを使用します。<span>import _ from 'ramda'; </span><span>import $ from 'jquery'; </span> <span>var Impure = { </span> <span>getJSON: _.curry(function(callback<span>, url</span>) { </span> $<span>.getJSON(url, callback); </span> <span>}), </span> <span>setHtml: _.curry(function(sel<span>, html</span>) { </span> <span>$(sel).html(html); </span> <span>}) </span><span>}; </span> <span>var img = function (url) { </span> <span>return $('<img />', { src: url }); </span><span>}; </span> <span>var url = function (t) { </span> <span>return 'http://api.flickr.com/services/feeds/photos_public.gne?tags=' + </span> t <span>+ '&format=json&jsoncallback=?'; </span><span>}; </span> <span>var mediaUrl = _.compose(_.prop('m'), _.prop('media')); </span><span>var mediaToImg = _.compose(img, mediaUrl); </span><span>var images = _.compose(_.map(mediaToImg), _.prop('items')); </span><span>var renderImages = _.compose(Impure.setHtml("body"), images); </span><span>var app = _.compose(Impure.getJSON(renderImages), url); </span><span>app("cats"); </span>
ログイン後にコピー最初のテストをテスト/example.js
で書きましょう<span>var app = (tags)=> { </span> <span>let url = <span>`http://api.flickr.com/services/feeds/photos_public.gne?tags=<span>${tags}</span>&format=json&jsoncallback=?`</span> </span> $<span>.getJSON(url, (data)=> { </span> <span>let urls = data.items.map((item)=> item.media.m) </span> <span>let images = urls.map((url)=> $('<img />', { src: url }) ) </span> <span>$(document.body).html(images) </span> <span>}) </span><span>} </span><span>app("cats") </span>
ログイン後にコピー<span>let flickr = (tags)=> { </span> <span>let url = <span>`http://api.flickr.com/services/feeds/photos_public.gne?tags=<span>${tags}</span>&format=json&jsoncallback=?`</span> </span> <span>return fetch(url) </span> <span>.then((resp)=> resp.json()) </span> <span>.then((data)=> { </span> <span>let urls = data.items.map((item)=> item.media.m ) </span> <span>let images = urls.map((url)=> $('<img />', { src: url }) ) </span> <span>return images </span> <span>}) </span><span>} </span><span>flickr("cats").then((images)=> { </span> <span>$(document.body).html(images) </span><span>}) </span>
ログイン後にコピー注:このコマンドの最後に-Wフラグを追加することもできます。モカに変更を監視し、テストを自動的に実行したい場合は、再実行でかなり速く実行されます。
Flickrモジュールのテスト<span>let responseToImages = (resp)=> { </span> <span>let urls = resp.items.map((item)=> item.media.m ) </span> <span>let images = urls.map((url)=> $('<img />', { src: url })) </span> <span>return images </span><span>} </span>
ログイン後にコピーに追加しましょう<span>let urls = (data)=> { </span> <span>return data.items.map((item)=> item.media.m) </span><span>} </span><span>let images = (urls)=> { </span> <span>return urls.map((url)=> $('<img />', { src: url })) </span><span>} </span><span>let responseToImages = _.compose(images, urls) </span>
ログイン後にコピーいくつかの新しい依存関係があります:jquery、アンダースコア、フェッチと約束のためのポリフィル。 それらをテストするには、JSDOMを使用してDOMオブジェクトウィンドウとドキュメントをポリフィルすることができ、Sinonパッケージを使用してFetch APIをスタブすることができます。
<span>// pure </span><span>function add(a<span>, b</span>) { </span> <span>return a + b; </span><span>} </span>
ログイン後にコピーログイン後にコピーログイン後にコピーログイン後にコピーtest/_setup.jsを開くと、モジュールが依存しているグローバルでJSDOMを構成します。
私たちのテストは、事前定義された入力を与えられた関数出力について主張するテスト/flickr.jsに座ることができます。 Global Fetchメソッドを「スタブ」またはオーバーライドして、HTTPリクエストを傍受および偽造して、Flickr APIを直接ヒットせずにテストを実行できるようにします。<span>// impure </span><span>var minimum = 21; </span><span>var checkAge = function(age) { </span> <span>return age >= minimum; // if minimum is changed we're cactus </span><span>}; </span>
ログイン後にコピーログイン後にコピーログイン後にコピーログイン後にコピー<span>// pure </span><span>var checkAge = function(age) { </span> <span>var minimum = 21; </span> <span>return age >= minimum; </span><span>}; </span>
ログイン後にコピーログイン後にコピーログイン後にコピーログイン後にコピーphew!小さなモジュールとそれを構成する機能をテストし、純粋な機能と途中で機能構成を使用する方法について学びました。 私たちは純粋なものを不純なものから分離しました。読みやすく、小さな機能で構成され、よくテストされています。 コードは、上記の不合理に純粋な
例よりも<span>// impure, splice mutates the array </span><span>var firstThree = function(arr) { </span> <span>return arr.splice(0,3); // arr may never be the same again </span><span>}; </span> <span>// pure, slice returns a new array </span><span>var firstThree = function(arr) { </span> <span>return arr.slice(0,3); </span><span>}; </span>
ログイン後にコピーログイン後にコピーログイン後にコピーログイン後にコピーを読み取り、理解し、変更するのが簡単で、コードをリファクタリングするときの私の唯一の目的です。 純粋な関数、それらを使用してください リンク フリスビー教授の機能プログラミングのほとんど適切なガイド - @drboolean - ブライアン・ロンズドルフによる機能プログラミングに関するこの素晴らしい無料の本は、私が出会うFPの最高のガイドです。 この記事の多くのアイデアと例は、この本から来ています。
Eloquent JavaScript - 機能的なプログラミング@Marijnjh - Marijn Haverbekeの本は、プログラミングの私のお気に入りのイントロの1つであり、機能的プログラミングに関する素晴らしい章もあります。アンダースコア - アンダースコア、ロダッシュ、ラムダなどのユーティリティライブラリを掘り下げることは、開発者としての成熟の重要なステップです。これらの機能を使用する方法を理解すると、記述する必要があるコードの量が大幅に削減され、プログラムがより宣言的になります。
-
- 今のところそれはすべてです! 読んでくれてありがとう。これがJavaScriptで機能的なプログラミング、リファクタリング、テストの良い紹介であることを願っています。 これは、これらのパターンを奨励または施行するReact、Redux、ELM、Cycle、Reactivexなどのライブラリの人気が高まっているため、現時点で波を起こしている興味深いパラダイムです。
- ジャンプして、水は暖かいです。
- 合理的に純粋な機能プログラミングに関するよくある質問
- 機能プログラミングにおける純粋な機能の重要性は何ですか?
機能的プログラミングは他のプログラミングパラダイムとどのように異なりますか?
機能プログラミングは、計算を数学機能の評価として扱い、状態および変化可能なデータの変更を回避するプログラミングパラダイムです。これは、プログラムが実行されたときにグローバル状態を変更するステートメントで構成されている命令的なプログラミングとは対照的です。機能プログラミングは、一流の市民としての機能など、高レベルの抽象化を促進し、声明の代わりに表現を使用したプログラミングを奨励します。これにより、推論が簡単なプログラミングのより宣言的で表現力豊かなスタイルにつながります。同じ入力に対して同じ出力を生成し、副作用を生成しません。例は次のとおりです。
関数add(a、b){
a b同じ結果が与えられ、外部の状態を変更しないと同じ結果。
JavaScriptで純粋な機能を使用することの利点は何ですか?関数の入力と出力を考慮するだけであるため、コードをより予測可能でテストしてデバッグしやすくします。また、明確でシンプルなプログラミングスタイルを宣伝するため、コードをより読みやすく保守しやすくします。さらに、純粋な機能は非常に再利用可能で構成可能であり、コードを減らすとより複雑な機能を構築することができます。 、彼らはまた、いくつかの課題を提示します。主な課題の1つは、JavaScriptが純粋に機能的な言語ではなく、副作用と可変データを可能にすることです。これは、機能に意図せずに副作用を導入するのを避けるために注意する必要があることを意味します。さらに、純粋な関数を使用すると、データの変異を避け、代わりに新しいデータを返す必要があるため、より冗長コードにつながる場合があります。同時性と並列性に特に適しています。純粋な機能には副作用がないため、人種の条件やデータの腐敗について心配することなく、並行して安全に実行できます。これにより、機能プログラミングは、特にマルチコアおよび分散コンピューティング環境で、同時および並列アプリケーションを開発するための強力なツールになります。関数プログラミングの関数構成とは?
関数構成は、機能プログラミングの基本的な概念です。 2つ以上の関数を組み合わせて新しい関数を作成することが含まれます。 1つの関数の結果は、次の関数への入力として使用されます。これにより、単純な関数から複雑な機能を構築し、コードの再利用性と読みやすさを促進できます。
機能的プログラミングの不変性は何ですか?これは、データ構造が作成されると、変更できないことを意味します。代わりに、データ構造を変更する場合は、目的の変更を伴う新しい構造を作成します。これにより、副作用が回避され、コードがより安全で推論が容易になります。
機能プログラミングは状態をどのように処理しますか?
機能プログラミングでは、副作用を回避するために状態は慎重に処理されます。状態を変更する代わりに、機能プログラミングはしばしば新しい状態を返す純粋な関数を使用します。これにより、状態は予測可能で管理しやすくなります。いくつかの機能的なプログラミング言語は、HaskellのMonadsなど、国家管理の高度な機能も提供しています。 。マルチコアや分散コンピューティングなど、並行性と並列性が重要な状況では特に役立ちます。機能プログラミングは、純粋な機能と不変性がデータの整合性を確保するのに役立つデータ処理と分析でも一般的に使用されています。さらに、フロントエンド開発では機能的なプログラミングの概念がますます採用されており、React.jsなどの一般的なフレームワークがコンポーネント開発に機能的なスタイルを使用しています。
以上が合理的に純粋な機能プログラミングの紹介の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

人気の記事

人気の記事

ホットな記事タグ

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック









