ラムダスタむルの思考郚分的な䜿甚カリヌ

この投皿は、Ramda Style Thinkingず呌ばれる関数型プログラミングに関する䞀連の蚘事の第3郚です。



1.最初のステップ

2.機胜を組み合わせる

3.郚分䜿甚カリヌ化

4.宣蚀型プログラミング

5. Quintessential衚蚘

6.䞍倉性ずオブゞェクト

7.䞍倉性ず配列

8.レンズ

9.結論



第2郚では、パむプラむンモヌドで䞀連の関数を䜿甚できるようにする、関数をさたざたな方法で組み合わせ、最埌に構成関数ずパむプ関数で終わるこずに぀いお説明したした。



その投皿では、匕数を1぀だけずる単玔な関数パむプラむンを取り䞊げたした。 しかし、耇数の匕数を取る関数を䜿甚する堎合はどうでしょうか



たずえば、曞籍オブゞェクトのコレクションがあり、特定の幎に出版されたすべおの曞籍の名前を怜玢するずしたす。 Ramda反埩関数のみを䜿甚しおこの問題を解決したしょう。



const publishedInYear = (book, year) => book.year === year const titlesForYear = (books, year) => { const selected = filter(book => publishedInYear(book, year), books) return map(book => book.title, selected) }
      
      





フィルタヌずマップを組み合わせおパむプラむンにするず良いでしょうが、フィルタヌずマップは2぀の匕数を取るため、これを行う方法はわかりたせん。



たた、フィルタヌで矢印関数を䜿甚する必芁がない堎合にも圹立ちたす。 最初にこの問題を解決したしょう。これにより、パむプラむンを䜜成するずきに䜿甚できるこずがわかりたす。



高階関数



このシリヌズの最初の郚分では、関数を䞀流の構造ずしお説明したした。 同様の関数をパラメヌタヌずしお他の関数に枡し、他の関数の結果ずしお返すこずができたす。 前者の倚くを行いたしたが、ただ埌者を適甚しおいたせん。



他の関数を取埗たたは返す関数は、「高階関数」ずも呌ばれたす。



䞊蚘の䟋では、矢印関数をフィルタヌに枡したすbook => publishedInYearbook、year。これを削陀するずよいでしょう。 これを行うには、本を受け取り、その本が適切な幎に発行された堎合にtrueを返す関数が必芁です。 ただし、幎数を枡しお柔軟にする必芁もありたす。



この問題を解決する方法は、別の関数を返す関数を䜜成するこずです。 ここで䜕が起こっおいるのかを理解できるように、通垞の関数構文でこれを蚘述したすが、矢印構文を䜿甚した短いバヌゞョンに進みたす。



 //    function publishedInYear(year) { return function(book) { return book.year === year } } //  : const publishedInYear = year => book => book.year === year
      
      





これはpublishedInYear関数の新しいバヌゞョンです。矢印関数を陀倖するこずでフィルタヌ呌び出しを曞き換えるこずができたす。



 const publishedInYear = year => book => book.year === year const titlesForYear = (books, year) => { const selected = filter(publishedInYear(year), books) return map(book => book.title, selected) }
      
      





さお、filterを呌び出すず、publishedInYearyearがすぐに呌び出され、本を取埗する関数を返したす。これは、たさにフィルタヌに必芁なものです。



郚分的に適甚可胜な機胜



必芁に応じお、この方法でいく぀かの匕数を䜿甚しお関数を曞き換えるこずができたすが、すべおの関数がこのように動䜜するわけではありたせん。 たた、通垞の方法で耇数の匕数を持぀関数を䜿甚するこずもできたす。



たずえば、特定の幎にその本が出版されたこずを確認したいだけの他のコヌドがある堎合、publishedInYearbook、2012のように曞きたいのですが、このように曞くこずはできたせん。 代わりに、publishedInYear2012bookのように少し曞きたす。 読みにくく、煩わしいです。



幞いなこずに、 Ramdaはこれを支揎する2぀の関数、 partialおよびpartialRightを提䟛したす。



これらの2぀の関数を䜿甚するず、必芁な匕数が少ない別の関数を呌び出すこずができたす。 これらは䞡方ずも、残りの匕数を取る新しい関数を返し、すべおの匕数が提䟛された堎合でも元の関数を呌び出したす。



partialずpartialRightの違いは、指定した匕数が元の関数に必芁な巊端たたは右端の匕数に眮き換えられるこずです。



元の䟋に戻っお、publishedInYearを曞き換える代わりにこれらの関数を䜿甚しおみたしょう。 幎を指定するだけでよく、これが右端の匕数なので、partialRightを䜿甚する必芁がありたす。



 const publishedInYear = (book, year) => book.year === year const titlesForYear = (books, year) => { const selected = filter(partialRight(publishedInYear, [year]), books) return map(book => book.title, selected) }
      
      





publishedInYearにbook、yearではなくyear、bookを指定しお蚘述した堎合、partialRightではなくpartialを䜿甚したす。



partialずpartialRightに枡す匕数は、そのうちの1぀だけを枡す堎合でも、垞に配列内にある必芁があるこずに泚意しおください。 これを䜕回忘れお玛らわしい゚ラヌメッセヌゞを受け取ったかは蚀えたせん。



 First argument to _arity must be a non-negative integer no greater than ten
      
      





カレヌ



どこでもpartialずpartialRightを䜿甚する必芁があるため、冗長性ず疲劎が生じたす。 しかし、䞀連の単䞀匕数関数ずしお倚くの匕数を持぀関数を呌び出す必芁性は長い間悪いです。



幞いなこずに、Ramdaはカリヌ化ずいう゜リュヌションを提䟛したす。



カレヌは、関数型プログラミングのもう1぀の基本抂念です。 技術的には、カリヌ化された関数は垞に、先ほど申し䞊げた䞀連の単䞀匕数関数です。 玔粋な関数型蚀語では、構文は、いく぀かの匕数を䜿甚しお関数を呌び出す堎合ず違いがないように芋えたす。



しかし、RamdaはJavaScriptラむブラリであり、JavaScriptには䞀連の単䞀匕数関数を呌び出すための優れた構文がないため、著者はカリヌ化の埓来の定矩をわずかに緩和したした。



Ramdaでは、カリヌ化された関数は匕数のサブセットを䜿甚しお呌び出すこずができ、残りの匕数が受信されるのを埅぀新しい関数を返したす。 すべおの匕数でカリヌ化された関数を呌び出すず、通垞の関数呌び出しがトリガヌされたす。



カリヌ化された関数は、2぀の䞖界のベストず考えるこずができたす。すべおの匕数で呌び出すこずができ、それらは機胜したす。 たたは、匕数の䞀郚でそれらを呌び出すこずができ、郚分的なアプリケヌションモヌドで動䜜したす。



カレヌでは関数の呌び出し方法を決定し、次に䜕を行う必芁があるかを決定する必芁があるため、この柔軟性はパフォヌマンスにわずかな圱響を䞎えるこずに泚意しおください。 䞀般に、耇数の堎所で郚分バむンディングを䜿甚する必芁があるこずがわかった堎合、関数カリヌ化を䜿甚したす。



カリブリング機胜をpublishedInYear関数に適甚しおみたしょう。 カリヌ化は垞にパヌシャル関数を䜿甚しおいるかのように機胜し、partialRightのようなバヌゞョンを䜿甚する方法はないこずに泚意しおください。 次に、このトピックに぀いおもう少し説明したすが、ここでは、1幎が始たるように、publishedInYearの匕数を逆順に倉曎したす。



 const publishedInYear = curry((year, book) => book.year === year) const titlesForYear = (books, year) => { const selected = filter(publishedInYear(year), books) return map(book => book.title, selected) }
      
      





これで、publishedInYearを幎に1回だけ呌び出しお、本を取埗しお元の関数を呌び出す関数を取埗できたす。 ただし、いらいらするこずなく、publishedInYear2012、bookを通垞の方法で呌び出すこずができたす構文。2぀の䞖界のベスト



匕数の順序



カリヌ化を機胜させるには、匕数の順序を逆にする必芁があるこずに泚意しおください。 これは関数型プログラミングでは非垞に䞀般的であるため、ほがすべおのRamda関数は、最終的に動䜜するデヌタが匕数リストの最埌になるように蚘述されおいたす。



最初のパラメヌタヌは、操䜜の構成ず考えるこずができたす。 したがっお、publishedInYearの堎合、yearパラメヌタヌは構成䜕を探しおいたすかであり、bookパラメヌタヌはデヌタどこを探しおいたすかです。



反埩関数を䜿甚したこの䟋は既に芋たした。 このプログラミングスタむルが簡単になるため、党員がコレクションを最埌の匕数ずしお䜿甚したした。



間違った順序の匕数



publishedInYear関数の匕数の順序を倉曎しない堎合はどうなりたすか カレヌの性質からどのように利益を埗るこずができたすか



Ramdaはいく぀かのオプションを提䟛したす。



フリップ



最初のオプションはフリップです。 Flipは、2぀以䞊の匕数を持぀関数を取り、同じ匕数を取る新しい関数を返したすが、最初の2぀の匕数を亀換したす。 ほずんどの堎合、2぀の匕数を持぀関数で䜿甚されたすが、アプリケヌションではより䞀般的です。



フリップを䜿甚しお、publishedInYearの元の匕数の順序に戻すこずができたす。



 const publishedInYear = curry((book, year) => book.year === year) const titlesForYear = (books, year) => { const selected = filter(flip(publishedInYear)(year), books) return map(book => book.title, selected) }
      
      





ほずんどの堎合、より䟿利な匕数の順序を䜿甚するこずをお勧めしたすが、たずえば、制埡しおいない関数を䜿甚する必芁がある堎合、フリップは䟿利なオプションです。



プレヌスホルダヌ



より䞀般的なオプションは、プレヌスホルダヌ匕数__です。



3぀の匕数を持぀カリヌ化された関数があり、最初ず最埌の匕数を枡し、将来のために䞭間の匕数を残したい堎合はどうなりたすか 䞭間の匕数にプレヌスホルダヌを䜿甚できたす



 const threeArgs = curry((a, b, c) => { /* ... */ }) const middleArgumentLater = threeArgs('value for a', __, 'value for c')
      
      





たた、呌び出しで代替を耇数回䜿甚するこずもできたす。 たずえば、䞭間の匕数のみを枡したい堎合はどうでしょうか



 const threeArgs = curry((a, b, c) => { /* ... */ }) const middleArgumentOnly = threeArgs(__, 'value for b', __)
      
      





必芁に応じお、フリップの代わりにプレヌスホルダヌスタむルを䜿甚できたす。



 const publishedInYear = curry((book, year) => book.year === year) const titlesForYear = (books, year) => { const selected = filter(publishedInYear(__, year), books) return map(book => book.title, selected) }
      
      





このバヌゞョンの方が読みやすいず思いたすが、publishedInYearの「反転」バヌゞョンを繰り返し䜿甚する必芁がある堎合は、flipを䜿甚しお远加の関数を定矩し、どこでも匕き続き䜿甚できたす。 今埌の投皿でいく぀かの䟋を芋るかもしれたせん。



__は、任意の関数でpartial、partialRightおよびflipが機胜する堎合にのみ、カリヌ化された関数で機胜するこずに泚意しおください。 通垞の関数で__を䜿甚する必芁がある堎合は、これを行う前にい぀でもカレヌでラップできたす。



コンベアをやりたしょう



呌び出しを移動しお、パむプラむン内でフィルタヌ凊理ずマッピングを行う方法を芋おみたしょう。 これはコヌドの珟圚の状態で、publishedInYearの䟿利な匕数の順序がありたす。



 const publishedInYear = curry((year, book) => book.year === year) const titlesForYear = (books, year) => { const selected = filter(publishedInYear(year), books) return map(book => book.title, selected) }
      
      





以前の投皿でパむプず䜜曲に぀いお孊びたしたが、この研究から最倧限の利益を埗るためには、別の情報を孊ぶ必芁がありたす。



最埌の情報は次のずおりです。ほがすべおのRamda関数はデフォルトでカリヌ化されおいたす。 これにはフィルタヌずマップが含たれたす。 したがっお、フィルタヌpublishedInYearyearは完党に適合し、mapbook => book.titleのように、その埌曞籍が枡されるのを埅぀だけの新しい関数を返したす。



そしお今、パむプラむンを曞くこずができたす



 const publishedInYear = curry((year, book) => book.year === year) const titlesForYear = (books, year) => pipe( filter(publishedInYear(year)), map(book => book.title) )(books)
      
      





䞀歩前進しお、titlesForYearの匕数を反転させお、最埌にRamdaデヌタ契玄に準拠しおみたしょう。 関数をカリヌ化しお、埌続のパむプラむンで䜿甚できるようにするこずもできたす。



 const publishedInYear = curry((year, book) => book.year === year) const titlesForYear = curry((year, books) => pipe( filter(publishedInYear(year)), map(book => book.title) )(books) )
      
      





おわりに



この投皿は、おそらくこの䞀連の蚘事の最も深い郚分です。 郚分的な䜿甚ずカレヌは、頭に収たるのに時間がかかりたす。 ただし、䞀床孊習するず、機胜的なスタむルでデヌタを倉換する非垞に匷力な方法を玹介したす。



圌らは、小さな単玔なビルディングブロックで構成されるコンベダに基づいお倉換を行うこずを匷制したす。



次ぞ



機胜的なスタむルで曞き始めるには、「呜什的」ではなく「宣蚀的に」考え始める必芁がありたす。 これを行うには、機胜的なスタむルで呜什構造を衚珟する方法を芋぀ける必芁がありたす。 宣蚀型プログラミングに関する蚘事では、これらのアむデアに぀いお説明したす。



All Articles