別のMonadガむドパヌト1基本

マむク・ノァニ゚



Haskellのファンコミュニティでは、すべおのHaskellプログラマヌがトレヌニング䞭に1぀以䞊のモナドガむドを䜜成する必芁があるずいう冗談でした。 そしお私も䟋倖ではありたせん。 しかし、私はこのトピックに関するガむドがたくさんあるこずを知っおいたす、それらの倚くは良いです-なぜ別のガむドを曞くべきですか 2぀の理由

  1. 私が芋た他の倚くのマニュアルよりも、モナドのいく぀かの偎面を説明できるず思いたす。
  2. 私はモナドを今よりもずっずよく理解し始めたした、そしお可胜な限り共有したいず思いたす。




前提条件


Haskellで䟋を曞くので、読者の皆さんは、ポリモヌフィズムや型クラスなどのトピックを含めお、それを知るこずが圹立぀でしょう。 この知識がなければ、資料を理解するのは困難です。 䜕十ものHaskell入門ガむドがすでに曞かれおいたす。これらは準備のできおいない読者に読む䟡倀があり、これらの蚘事のシリヌズに戻りたす。



しかし、モナドの理論をこの蚘事の芳点から蚘述しおいるにもかかわらず、数孊の非垞に抜象的な分岐であるカテゎリヌの理論を知る必芁はありたせん。 もちろん、カテゎリヌ理論の知識は害にはなりたせんが、提瀺された資料を理解する必芁はありたせん。 私は、プログラミング蚀語に適甚されるモナドを孊習する前にカテゎリヌ理論が必芁だず蚀う人を信じおいたせん-これはそうではありたせん。 あなたがそれを研究した堎合、それは良いこずですが、そこから甚語を䜿甚するこずの利点がわかりたせん。





の拒吊...


次の2぀の理由で、モナドの䞖界にあるすべおを教えようずは思いたせん。 1぀目は非垞に長い時間であり、2぀目はすべおがわからないため、おそらく決しおわかりたせん。 玔粋な抂念レベルでのモナドの理解、それらが有甚である理由、それらの操䜜方法、および最も䞀般的に䜿甚される䞀般的なモナドを提䟛したいず思いたす。 この䞀連の蚘事の最埌にあるリンクから、モナドをより深く孊ぶこずができたす。



毎日の仕事ですぐに䜿甚できる倧量のコヌドを期埅しないでください。 これは「レシピブック」ではありたせん モナドを䜿甚しおプログラムを䜜成するずどうなるかを理解する必芁があるず本圓に信じおいたす。このガむドはモナドを詳现に説明するために曞かれおいたす。 それに加えお、他のマニュアルリンクを参照を読んで実甚的な問題に察する最良のモナドの解決策を芋぀けるこずができたす。私の目暙は、党䜓像を抂説し、モナドずその䜜業を本圓に理解できるようにするこずです。



最埌に、私はあなたが私に蚀いたいこずを完党に理解しおほしいので、圌らがあなたに向かっお叫ぶたで䞻な考えを繰り返しお繰り返すこずをあなたに通知しおいたす。 モナドはいく぀かの文章で説明できないので、これは退屈ではないこずを願っおいたす。 自分でコヌヒヌを飲み、怅子が快適であるこずを確認しおください-理解には時間がかかりたす。



動機モナドに぀いお考える必芁があるのはなぜですか


私の知る限り、最初のモナドはHaskellで䜿甚され、Eugenio MoggiずPhilip Wadler私は比范できない2぀の巚人の仕事に基づいおいたす。 それ以来、それらは他の蚀語、特に機胜的な蚀語で登堎したした。 しかし、なぜ読者おそらく関数型プログラミングの薬を詊したこずのないプログラマヌがモナドを心配する必芁があるのでしょうか



関数型プログラミングの䞻な考え方は、 玔粋な関数をできるだけ広く䜿甚するこずです。 玔粋な関数はブラックボックスです。 圌女がしおいるこずは、1぀以䞊の匕数を取り、䜕かを蚈算し、結果を返すこずだけです。 圌女は副䜜甚がありたせん 。 ファむルず゜ケットぞの読み取り/曞き蟌み、コン゜ヌルぞの出力、グロヌバル倉数ぞの倉曎、䟋倖凊理などはありたせん。 ここでの利点は、玔粋な関数の動䜜が厳密に定矩されおいるこずです。 垞に同じ匕数に同じ倀を返したす。 玔粋な関数は、より予枬可胜で、テストが簡単で、゚ラヌが発生しにくいものです。 {1}比范のために、unclean関数副䜜甚がありたすは、いく぀かの同䞀の呌び出しに察しお必ずしも同じ結果を蚈算したせん。 たずえば、関連するグロヌバル倉数の倀が倉曎された堎合、たたは読み取られたファむルの内容が異なる堎合、回答が異なる堎合がありたす。 䞍玔な関数はテストが難しく、倚くの゚ラヌが発生しやすく、関数が倱敗する倚くの状況がありたす。 これらの理由から、関数型プログラミング蚀語では、可胜な限り玔粋な関数を䜜成するこずをお勧めしたす。



ただし、玔粋な関数のプログラムは制限が倚すぎたす。 副䜜甚を䜿甚しおプログラムを簡単に䜜成できる堎合がありたすが、玔粋な関数でのみ苊痛を䌎う䜜成できたす。 たた、他のいく぀かのケヌスでは、副䜜甚なしで行うこずは䞍可胜です。 たずえば、あるフォルダヌから別のフォルダヌにファむルをコピヌするプログラムは、ファむルシステムずやり取りしお倉曎したす。 玔粋な関数がファむルの読み取りず曞き蟌みを蚱可されおいない堎合そしおこれらは副䜜甚です、この問題を解決するこずはできたせん。 したがっお、関数型蚀語であっおも副䜜甚に察凊する方法が必芁です。



関数型蚀語には、玔粋ず䞍浄の2぀のタむプがありたす。 䞍玔なFSScheme、OCamlはこの問題を気にしたせん副䜜甚のある関数を曞くこずができたすが、ダヌティFSのプログラマヌは通垞、特別な必芁なしにこれを避けたす。 玔粋なFYHaskellなどはよりハヌドコアです。通垞、副䜜甚を䌎う関数の盎接的な曞き蟌みを犁止したす「盎接」ず曞いた理由がすぐにわかりたす。 したがっお、ご想像のずおり、玔粋なプログラミング蚀語の副䜜甚のトピックは、長い間研究の䞻な分野の1぀でした。



モナドはこの問題を解決する鍵であるこずが刀明したした。 より正確には、キヌの1぀。他のアプロヌチは他のFYで発明されおいたす。オプションずしお「Cleanの䞀意性タむプ」。モナドを䜿甚するず、蚀語の玔床に違反するこずなく副䜜甚のある蚈算を䜿甚できたす。 モナドず型システムを䜿甚するず、副䜜甚のある蚈算を他の蚈算から分離するこずができ、盞互に干枉したせん。 副䜜甚なしにコヌドのすべおの利点が埗られ、これにより型システムが保蚌されたす。 同時に、必芁に応じお副䜜甚を実行できたす。 そしお、これは非垞に匷力な抂念です。



そしお、これで十分ではないかのように、モナドには副䜜甚を抑えるだけでなく、他にも倚くの甚途があるこずがわかりたした。 モナドは非垞に甚途の広いツヌルであり、これを䜿甚するず、透過的な動䜜でさたざたなタむプの蚈算を敎理できたす。 䞀郚のプログラムは倧幅に簡玠化されおいたす。 倚くの堎合、モナドコヌドは、非モナドコヌドよりも短く、理解しやすいです。 この珟象の䟋を分析したす。 䞀般に、モナドは関数型蚀語の副䜜甚以倖でも有甚です。



モナドは、プログラミング蚀語の理論における玠晎らしいアむデアの1぀であり、探玢する䟡倀がありたす。



定矩モナドずは䜕ですか


モナドは、関数、関数の適甚、および関数の構成に察する䞀般化であり、暙準の関数ず比范しお蚈算の抂念が抜象化されおいたす。




その過皋で、私はあなたにモナド自䜓ずそれらがどのように機胜するかだけでなく、なぜ圌らが以前に䌚ったこずのないプログラマを萜胆させるのかを説明したいず思っおいたす。 ヒントこれは、プログラマヌが十分に賢くないか、カテゎリヌ理論を知らないためではありたせん。



コンピュヌティングの抂念


さお、「コンピュヌティングの抂念」ずいう衚珟から定矩の分析を始めたしょう。



最も単玔で最も予枬可胜な蚈算は、通垞の玔粋な関数぀たり、関数の数孊的な定矩です。 簡単にするために、1぀の入力匕数を1぀の出力にマップする関数を考えたす。  カリヌ化手順を䜿甚しお、耇数の匕数を持぀関数を1぀の匕数を持぀関数に枛らすこずができたす。これに぀いおは埌で詳しく説明する必芁がありたす。  垞に同じ結果を同じ入力パラメヌタヌに返す必芁がありたす。 Haskellのような匷く型付けされた蚀語では、関数には型定矩がありたす。぀たり、型aずbの堎合、関数は型aの倀を型bの倀にマップしたす。 Haskellでは次のように衚瀺されたす。



f :: a- > b




ここで、二重コロン「::」は「次のタむプを持぀」こずを意味したす。 したがっお、関数fの機胜タむプはa-> bです。これは、関数がタむプaの倀を取り、タむプbの倀を返すこずを意味したす。 実際には、aずbは通垞、具䜓的な型Int、Float、String ...を持っおいたすが、Haskellでは、関数は匕数の型に関係なく機胜したす。 {3}



したがっお、玔粋な関数は最も単玔な「蚈算の抂念」です。 そしお、どのような蚈算がただ存圚したすか それらの倚くがあり、あなたは倚くに粟通しおいたす。 これには次の蚈算が含たれたす。





通知ファむルたたはコン゜ヌルを操䜜するずきの入力/出力を意味するために、「入力/出力」たたは略しおI / Oずいうフレヌズを䜿甚したした。 I / O操䜜は副䜜甚をもたらすこずが知られおいたす。 I / O操䜜を関数の入出力倀ず混同しないでください。



これらの蚈算を通垞のプログラミング蚀語CたたはJavaでどのように䜿甚するかに぀いおもう1぀考えおください。 入出力操䜜の蚈算 問題ありたせん CおよびJavaの任意の機胜。 䟋倖の呌び出しはどうですか Cでは、䟋倖の蚀語サポヌトがないため、これは少し耇雑ですが、障害が発生した堎合に゚ラヌコヌドを返すこずができたす。 たたは、経隓豊富な䜎レベルのプログラマヌであれば、䞀般にsetjmp / longjmpで゚ラヌを凊理できたす。Javaでは、どこかで凊理されるこずを期埅しお、単に䟋倖をスロヌしたす。 䟋倖に加えお、ただ条件がありたす-それをどのように扱うか はい、䞀般的には簡単です。CおよびJavaでは、グロヌバルおよびロヌカルの倉数をさたざたな方法で読み曞きできたす。 そしお、倱敗するかもしれない蚈算 それらは䟋倖の退化したケヌスず芋なすこずができるので、やはり問題はありたせん。 最埌に、倚くの倀を返す蚈算に぀いおはどうでしょうか ここで、倚数の倀ずは、倚数の結果を含む1぀のオブゞェクトではなく、C構造䜓やJavaオブゞェクトではなく、耇数の別個の結果を「䞊列に」返すこずができる関数のこずです。 CたたはJavaでこれを行う方法は完党には明らかではありたせん。 {4}



次の点に泚意するこずが重芁です。すべおの堎合においお、埓来のコンピュヌティングの抂念に぀いおはもう話しおいたせん。入力パラメヌタから出力ぞの通垞のマッピングに加えお、「どこか」、「䜕か」が発生するからです。 さらに、コンピュヌティングの独自のコンセプトを持぀他のタむプの「他の䜕か」がありたす。 通垞、プログラムを䜜成するずきにこれに぀いお心配するこずはありたせん。 「関数」は数孊的な意味での関数ずたったく同じではないこずを理解しおいたす。 結局のずころ、入力/出力、䟋倖、グロヌバル倉数の倉曎などの副䜜甚がありたす。 ほずんどのプログラマヌにずっお、これは重芁ではありたせん。グロヌバル倉数の倉曎による䞍快な゚ラヌをキャッチするたで、プログラムが䟋倖で突然停止するたで、たたはこれらすべおの非機胜的性質によっお匕き起こされる他の問題が発生するたで「機胜」。 したがっお、できるだけ玔粋な関数を䜿甚したいず思いたす。 したいず思いたすが、これが䞍可胜な堎合があり、「䜕か他のこず」、぀たり副䜜甚を䌎う蚈算を行う必芁がありたす。



結論は1぀だけです。2぀の怅子に座りたいです。 {5}可胜な限り玔粋な関数でコヌドを蚘述し、これのすべおの利点を埗たすデバッグ、怜蚌を容易にしたす...しかし、この「䜕か」を制埡された方法で凊理したいず思いたす。特定の状況では、出口かそこらがより良いです。 そしお、これがモナドが私たちに蚱しおいるこずです。



しかし 最埌の段萜のキヌフレヌズは「制埡された方法で」です。 このメカニズムがCたたはJavaの堎合ず同じように機胜する堎合、もちろん、これらの非関数型蚈算の倚くを䜿甚しお問題を解決したすが、関数型プログラミングの利点も倱いたす。 結局のずころ、関数がクリヌンであるこずを保蚌するものではなく、ここでは型チェックも圹に立たないでしょう。 コンピュヌティングの他の抂念ず連携するためのある皮の䜓系的なアプロヌチが必芁です。これは、コヌドの玔床に違反したせん。



次に、玔粋な関数、玔粋な関数の適甚、および玔粋な関数の合成の有甚な抂念を怜蚎し、同じ目暙を実装するモナド法ず比范したす。



機胜、機胜の適甚アプリケヌションおよび機胜の構成


以前、Haskellは関数の入力および出力パラメヌタヌのタむプを決定するために特別な゚ントリを䜿甚するこずを述べたした。 入力タむプがaで出力タむプがbの関数fの堎合、゚ントリは次のようになりたす。



f :: a- > b




したがっお、fのタむプはa-> bです「from a to b」ず読みたす。 入力倀を2倍にする関数のより具䜓的な䟋を次に瀺したす。



f :: Int- > Int

f x = 2 * x




fは敎数型を取り、敎数を2倍しお別の敎数を返すため、Int-> Int型です。



関数の実行は簡単です。そのため、匕数に適甚したす匕数が1぀あるず仮定したす。 これは通垞、関数に匕数を割り圓おるこずで行われたす。



f 2- 関数「f 2」倀= 4。




Haskellでは、他の倚くのプログラミング蚀語のように、匕数が括匧で囲たれおいないこずに泚意しおください。



カレヌ



実際には、単䞀の匕数関数では倚くのタスクに十分ではありたせん。 2぀の匕数の関数をどのように定矩したすか たずえば、2぀の敎数匕数を取り、それらの2乗の合蚈を返す関数qを䜜成するにはどうすればよいですか 関数の本䜓は簡単に蚘述できたす。



q x y = x * x + y * y




関数タむプの眲名が省略されたした。 おそらく、あなたはある皮のオプションを期埅しおいたす



q :: Int Int- > Int




たたはおそらくこれ



q : :Int 、 Int  -> Int




実際、この関数のタむプは次のようになりたす。



q :: Int- > Int- > Int




矢印「->」は右結合なので、゚ントリは次のこずを意味したす。



q :: Int ->  Int- > Int 




今では面癜そうです。 Haskellでは1぀の匕数の関数この堎合はxになる2぀の匕数の関数は、1぀の匕数の別の関数を返し、次の匕数yを受け取っお結果を返したす。 Haskellでは、他のFYず同様に、関数は他の関数の倀ずしお返される可胜性があるため、これは正しいです。 蚀い換えるず、関数はUFでは単に異なるデヌタ型です。このように、耇数匕数関数を単䞀匕数ずしお衚珟する方法はカリヌ化ず呌ばれたすHaskell Curryの名前はHaskellずも呌ばれたす。手順など、必芁に応じお。 明確にするために、敎数を返す4぀の敎数匕数w、x、y、およびzを持぀関数rを䜿甚したす。



r :: Int- > Int- > Int- > Int- > Int

r w x y z = ... は、w、x、y、およびzの関数です




右矢印は次を提䟛したす。



r :: Int ->  Int ->  Int ->  Int- > Int   

r w x y z = ... は、w、x、y、およびzの関数です




ここで、rは1぀の敎数匕数wの関数であり、タむプInt->Int->Int-> Intの関数を返したす。 その関数は、敎数この䟋ではxに適甚されるず、タむプInt->Int-> Intの関数を返したす。 次の関数は、敎数䟋ではyに適甚され、型Int-> Intの関数を返したす。これは、別の敎数zに適甚されるず、敎数-呌び出しの結果rwxyzを返したす。 、実際には、rwxyz。 そしお、これはカレヌず呌ばれたす。 Haskellは自動的に関数をカリヌ化したす。 カリヌ化は非垞に䟿利です。匕数を䞀床に1぀ず぀枡すこずができ、䞀床にすべおを枡すこずはできたせん。たた、これらの郚分的に適甚された関数は、単独で非垞に圹立぀こずがよくありたす。 たた、カレヌは抂念的にはこれからは1぀の匕数の関数に぀いお考えるだけで十分であり、それ以䞊のこずはありたせん。 いいね




Haskellには特別な$挔算子がありたす。これは関数挔算子です。 次のタむプがありたす。



 $  ::a- > b  -> a- > b




Haskellでは、蚘号䞭眮挔算子は括匧で囲たれた同じ名前の関数ず同等です。したがっお、衚蚘f $ 2は衚蚘$f 2.ず同等です。挔算子は通垞、䟿宜䞊関数圢匏で定矩されたす。蚀語の入門資料を参照しおください。詳现を知りたい堎合は、ここで挔算子を䜿甚するこずがよくありたす。



衚蚘法は、任意のタむプaおよびbに察しお、この挔算子がaからbたでの関数を最初の匕数ずしお受け取り、それをタむプaの2番目の匕数に適甚し、タむプbの結果を返すこずを意味したす。 関数型蚀語では、関数を匕数ずしお他の関数に枡すこずは䞀般的であるず考えられおいるため、問題はありたせん。 次の結論を出すこずができたす。



f 2- >は4を返したす

f $ 2- >も4を返したす

 $  f 2- >ここでは4が返されたす




同じこずを曞くための3぀の異なる方法がありたす。



ここでは、関数を実行するために匕数を関数に眮き換える方が技術的に簡単なので、$挔算子は実際には必芁ありたせん。 しかし、興味を匕くために、「逆アプリケヌション」挔算子を指定し、それを>>呌び出し、同じ匕数を逆の順序で受け取るこずができたす。



 > $>  :: a ->  a- > b  -> b

x > $> f = f x- = f $ xず同じ




これを「挔算子は倀xを取り、それに関数を適甚しお結果を返す」ず読むこずができたす。 UNIXシステムに粟通しおいる堎合は、Unixパむプラむンパむプ、|が同様に機胜するこずに気付いおいるかもしれたせん。 あなたは圌にいく぀かのデヌタを䞎え、圌は圌に続くプログラムを適甚したす。 䟿利な堎合は関数挔算子を䜿甚できたすが、通垞はたったく䜿甚せず、関数の匕数を単玔に眮き換えたす。



関数の䜿甚に぀いお説明したので、次の重芁なトピックは関数の構成です。 そしお、これは本圓に重芁なトピックです。 2぀の関数fずg、および次の圢匏のx倀があるずしたす。



x :: a

f :: a- > b

g :: b- > c




ここで、a、b、cはいく぀かのタむプです。 これらのx、f、およびgを䜿甚しお以䞋を実行できたす。xを取埗し、それに関数fを適甚しタむプbの倀を取埗、関数gを結果に適甚したす。 タむプxの倀はタむプbの倀に倉換され、その埌、発生したこずはタむプcの倀に倉換されたす。 Haskellで曞くこずは蚀うより簡単です



g  f x 




しかし、これは、型fずgに互換性がある堎合、぀たり、関数fの結果が関数gの匕数ず同じ型である堎合にのみ機胜したすこの堎合、型bです。 ある関数の別の関数ぞの適甚は別の方法で解釈できたす。それぞれ、タむプの2぀の関数fおよびg、a-> bおよびb-> cを取り、タむプa-> cの3番目の関数を䜜成したす。 匕数xに適甚するず、タむプcの結果が埗られたす。 2぀の関数を3番目の関数に結合するこの考え方は、関数の合成ず呌ばれたす。 Haskellは単玔な関数合成挔算子も定矩しおいたす



 。  :: b- > c  ->  a- > b  ->  a- > c 

g 。 f = \ x- > g  f x 




ここでは、衚蚘「\ x-> ...」を䜿甚したす。これは、1぀の匕数xを持぀ラムダ匏たたは、同じこず、匿名関数を瀺したす。 これは、合成挔算子が匕数ずしお2぀の関数を取り、3番目の関数を返す方法です。 繰り返しになりたすが、FYでは、匕数ずしおの関数ず戻り倀ずしおの関数は、すべおのステップで発生する非垞に䞀般的な珟象です。



関数が間違った順序で続くず、合成挔算子で迷惑が発生するこずがありたす。 しかし、「逆構成挔算子」を曞くこずができたす。>



 >。>  ::a- > b  ->  b- > c  ->  a- > c 

f >。> g = \ x- > g  f x 




function> $>の逆挔算子でも衚珟できたす。



 >。>  ::a- > b  ->  b- > c  ->  a- > c 

f >。> g = \ x- > x > $> f > $> g




たたはさらにシンプル-合成挔算子を䜿甚



 >。>  ::a- > b  ->  b- > c  ->  a- > c 

f >。> g = g f




the>。>挔算子のシグネチャは少し明確で、関数が構成されたずきに䜕が起こるかを瀺しおいたす。 関数fずgを取り、新しい関数を蚈算したす。 圌女をhず呌びたしょう。 倀にhを適甚するず、最初に倀にfを適甚し、次に結果にgを適甚するず同じ結果になりたす。 これが関数合成ずは䜕か-いく぀かの関数から他の関数​​を䜜成する方法です。



䟋を分析したしょう



f :: Int- > Int

f x = 2 * x



g :: Int- > Int

g y = 3 + y



h :: Int- > Int

h = g f- たたは同じf>。> g




ここで関数hは䜕をしおいたすか 敎数を取埗し、2で乗算し、3を加算したす。぀たり、次のオプションず同等です。



h :: Int- > Int

h x = 3 + 2 * x




関数の構成はそれほど倧したこずではないように思えるかもしれたせん-実際には、これは関数型プログラミングの䞻芁なポむントの1぀です。 合成により、既存の関数をより耇雑な関数にリンクし、匕数を䜿甚した手䜜業を省略できたす。 そしお、「hは、関数y = fxを蚈算するこずによっお最初に取埗され、次に関数h = gyを蚈算するこずによっお取埗される関数」ず蚀う代わりに、「hは最初に適甚される関数ですf、g。」 䞭間゚ンティティがなければ、コヌドはより簡朔で高レベルになりたす。 10個の関数を次々に呌び出さなければならないず想像しおください。 䞭間結果を䜜成するず、次のような結果になりたす。



f11 x =

させる

x2 = f1 x

x3 = f2 x2

x4 = f3 x3

x5 = f4 x4

x6 = f5 x5

x7 = f6 x6

x8 = f7 x7

x9 = f8 x8

x10 = f9 x9

x11 = f10 x10

で

x11




ずおも疲れたすよね 次に、関数の構成を芋おください。



f11 = f10 f9 f8 f7 f6 f5 f4 f3 f2 f1




たたは、同じこず



f11 = f1 >。> f2 >。> f3 >。> f4 >。> f5 >。> f6 >。> f7 >。> f8 >。> f9 >。> f10




短いだけでなく、より盎感的です。 「f1、f2、f3などを䜿甚するず、f11が埗られたす」。 ずころで、合成を䜿甚しお匕数なしで関数を蚘述するこの方法は、「無意味なスタむル」ず呌ばれたす。 皮肉なこずに、「ドット」挔算子。は「無意味なスタむル」で非垞によく䜿甚されたす-通垞のコヌドよりも匷力です。 関数の匕数を省略しおいるため、「無意味」ではなく「匕数のないスタむル」ず蚀う方が正しいでしょう。



反射のテヌマ、玠材の匷化





モナド関数、モナド倀


これたでのずころ、私が語ったこずはすべお、非垞に簡単でした。 次に、より耇雑なものに進みたす。



前に、モナドの本質は、玔粋な関数の蚈算ずは異なる蚈算の圢で、関数の構成ず適甚の抂念を䞀般化するこずであるず述べ、「䞍玔物」のいく぀かの䟋を怜蚎したした。 モナドの定矩から、単玔に入力倀を蚈算するこずに加えお、䜕か他のこずを行う「高床な関数」が埗られるこずがわかりたす。 スケマティック擬䌌Haskell蚀語では、次のようにこれらの「高床な関数」を曞くこずができたす。



f :: a- [その他]-> b




ここで、fは拡匵関数、aは匕数のタむプ、bは結果のタむプ、「䜕か他のもの」はコンピュヌティングのさたざたな抂念に固有のものです。 Haskellでは、「蚈算の抂念」ずいう蚀葉は、特にモナドにありたす。 私たちはただそれが䜕であるかを知らないので、今のずころ、私の蚀葉を䜿っおください。「高床な関数」は「単項関数」ずしお理解できたす。 これは暙準的な甚語ではなく、通垞の玔粋な関数ず区別するために呌び出したす。



もちろん、 "-[something other]->"ずいう衚蚘はHaskellでは無効です。 少し埌で、それが実際にどのように芋えるかを確認し、それが明確になるこずを願っおいたす。 䞊蚘の蚈算の抂念を比范するために、これらの衚蚘法に固執したす。 Haskellのモナドに察応する蚈算名の各抂念を瀺したす。



  1. コン゜ヌルたたはファむルぞの入出力操䜜を実行する関数。 I / O操䜜はIOモナドに察応するため、次のように蚘述したす。

    f :: a- [IO]-> b
    ずころで、埌で説明するように、IOモナドには他の甚途がありたす。
  2. 䟋倖をスロヌできる関数。 いく぀かのタむプのモナドがそれらに察応したす

    f :: a- [゚ラヌ]-> b
  3. グロヌバルたたはロヌカル状態ず盞互䜜甚する関数。 これは、Stateモナドです

    f :: a- [状態s]-> b
  4. 倱敗する可胜性のある機胜。 倚分モナドに぀いお話しおいる

    f :: a- [倚分]-> b
  5. 同時に耇数の倀を返す関数。 モナドリストリスト

    f :: a- [リスト]-> b




Haskellのリストは構文糖のために少し異なっお芋えるため、「リスト」ずいう単語を小さな文字で曞きたした。したがっお、別個の単語は必芁ありたせん。



埌でこれらのすべおのモナドの䟋を瀺したす。次に、入出力操䜜を実行する関数、぀たりIOモナドに関連する関数を怜蚎したす。 疑䌌レコヌドがありたす



f :: a- [IO]-> b




fは、モナドIOで機胜するaからbたでの関数であるず蚀えたす。 䞊で述べたように、これは無効な構文です。 Haskellでは、入力たたは出力パラメヌタヌでそれを囲むこずにより、モナド関数の単進性を型でラップする必芁がありたす。 原則ずしお、次のようなモナド関数を䜜成するための2぀のオプションがありたす。



f :: IO a- > b




たたは



f :: a- > IO b




Haskellはモナド関数に2番目の圢匏の衚蚘法を䜿甚しおいるこずがわかりたす。



f :: a- > m b




任意のモナドm; IOの堎合など。 筋金入りの劎働者にずっお、各関数がf :: ca-> bずいう圢匏のcomonadの抂念があるこずに泚意しおください。䞀郚のcomonad cに぀いおは、この質問を今埌の蚘事のために残したしょう。



さお、゚ントリ「f :: a-> mb」の背埌にあるものは本圓に䜕ですか レコヌドずは、タむプaの倀を取り、タむプmbの倀を返す通垞の玔粋な関数fがあるこずを意味したすそれらが䜕であれ。 そのため、Haskellでは、モナド関数は、モナドの戻り倀型を持぀玔粋な関数です。 ぀たり、玔粋な関数は通垞の倀を取り、モナドを返したす。 それはどういう意味ですか



゚ントリ「mb」には説明が必芁です。 b-これは䜕らかのタむプです。 mは䜕らかのモナドを衚したす。 しかし、Haskellのmの正確な意味は䜕ですか Haskellでは、「m」は型コンストラクタヌである必芁がありたす。これは型に関する特別な関数です。匕数を取り、型を返したす。 これは芋た目ほど奇劙ではありたせん。 Haskellのタむプが[Int]のように芋える「敎数のリスト」の抂念を考えおみたしょう。 「䜕かのリスト」郚分は、特定のタむプIntを受け取り、別のタむプ敎数のリスト、[Int]を返すタむプコンストラクタヌずしお理解できたす。 Haskellの角括匧はリストを瀺すために固定されおいたすが、独自の型コンストラクタを定矩できたす。 たた、あらゆる倚盞型には独自のコンストラクタがありたす。 最も単玔な倚盞型の1぀は、倚分、



デヌタ 倚分 a = Nothing | ただ




ここでは、倚分は型aず呌ばれるを取り、出力倀ずしお新しい型を生成する型コンストラクタヌであるず述べおいたす。 タむプIntをaに眮き換えるず、新しいタむプMaybe Intが埗られたす。これは次のように蚘述されたす。



デヌタ 倚分 Int = Nothing | ちょうどint




したがっお、倚分、1぀の型を別の型にマップする型関数です。



モナドは、Haskellにあるように、叀い型をラップしお新しい型を生成する型コンストラクタです。そしお実際、IOモナドは、IO Bool、IO Int、IO Float、IO Char、IO Stringなどの型が生成される型コンストラクタです。これらはすべおHaskellで有効なタむプです。同様に、Maybeモナドの堎合、有効なタむプMaybe Bool、Maybe Intなどが構築されたす。モナドコンストラクタヌによっお䜜成された型を「モナド型」ず呌びたす。IO Bool、Maybe Intなど-これらはすべおモナド型です。



泚意事項Haskellのすべおのモナドは型コンストラクタヌでなければなりたせんが、すべおの型コンストラクタヌがモナドではありたせん。埌で芋るように、モナドは型コンストラクタでなければなりたせん。モナドに察しお特別な操䜜を定矩する必芁があり、それらはいく぀かの「モナドの法則」を満たさなければなりたせん。




私たちは非垞に重芁な質問に来たすモナド型を衚す倀は䜕をしたすか私はそれらを「単項の意味」ず呌びたす。たずえば、Maybe Int倀ずは䜕ですかIO Float-それは䜕ですか



モナドを「理解するのが難しい」ように芋えるものに出䌚ったずころです。



芁玄したしょう。



  1. 「玔粋な関数」ずいうおなじみの抂念がありたす。぀たり、䜕もせずに、あるタむプの入力倀を別のタむプの出力倀たたは同じものに倉換する関数です。
  2. , - . «- » / , , , , . , « ». , , .
  3. Haskell — , - . «».




ここで、「モナドの意味」の本質に぀いお私たちは䜕を蚀うこずができるかずいう質問を再定匏化したすか



答えは圌らは本圓に盎感的ではありたせん 。盎感的には、モナド関数䞀郚のデヌタを他のデヌタに倉換する以倖のこずを行うものの抂念。 「単項の意味」の抂念はたったく盎感的ではありたせん。 Haskellでは、モナド関数の出力倀を瀺すのが慣習であるだけです。これらのモナドの意味が実際に䜕であるかを通しおモナドを理解しようずするず、無駄に時間を費やしたす。気にしないでくださいそれだけの䟡倀はありたせん



しかし、Haskellの文献には、モナドの意味を説明する2぀の䞀般的な方法がありたす倚くのマニュアルが眪を犯す愚かな方法がたくさんありたす。



1. ma型のモナド倀䞀郚のモナドmの堎合は、䜕かを実行しおa型の倀を返す特別な皮類の「アクション」です。アクションの本質は特定のモナドに䟝存したす。



2.タむプmaのモナド倀䞀郚のモナドmは、タむプaの倀が栌玍されるコンテナです。



モナドの意味のリフレクションを通しおモナドを研究するこずは間違ったアプロヌチであり、モナド関数のリフレクションを通しお正しいです。定矩にはある皋床の意味があるこずを玍埗させたいず思いたす1。しかし、埌で芋るように、定矩2はモナドを研究する間違った方法です。ほずんどのモナドはコンテナではありたせんが、コンテナのように動䜜するものもありたす。



私たちの機胜を芋おみたしょう、それが出発点ずしお、かなり明確であるこずを願っおいたす



F :: - >メガバむト




次に、関数fxxはa型はmb型になりたす。



x :: a

fx :: mb




fxは珟圚、「単項の意味」であり、完党に盎感的ではありたせん。別の機胜を怜蚎しおください



g :: a ->   -> a

gx   = x




gは文字通り次のこずを行いたす。任意の型aの倀を取り、関数にラップするため、空の倀をgに枡すこずで結果を取埗できたす。{6}空の型ず倀は、括匧で同じようにHaskellで蚘述されたす。これは、私たちにずっお重芁ではない型/倀です。「空」ずいう蚀葉は、この倀が私たちにずっお関心を衚しおいないこずを意味したす。次に䟋を瀺したす。



h = g 10

h   -数倀10が蚈算されたす




さお、gfx関数を発明するこずで䜕が埗られたすかタむプを芋おみたしょう。



fx :: mb- 䞊蚘を参照

g :: a ->   -> a

g  fx  ::   -> mb




したがっお、関数gfxはタむプ-> m bです。぀たり、空の倀を取り、単項の倀を返したす。䞀方、これを芋るず、これは空の倀䜕があっおもを型bの倀に倉換するず同時に、「䜕か他のこず」を実行する単項関数です。「他の䜕か」は、どのモナドが䜿甚されるかに䟝存したす。それはある皋床理にかなっおいたす。



これが私の考えです。 mb型のモナド倀が䜕であるかを理解する必芁があるず思う堎合、-> mb型のモナド関数、぀たり、空の倀をb型の倀にマッピングするだけでなく、䜕かを実行する関数ずしお考えるのが最善です他の䜕か。タむプmbの倀がタむプ-> mbの関数であるかのように、異なる方法でのみ蚘述されたす。぀たり、モナドの意味は「秘密の機胜」です。したがっお、それらは「アクション」ず呌ばれるこずが倚く、機胜に関連付けられおいたすが、完党な機胜ではありたせん。 「アクションを実行する」ず蚀うこずもありたすが、これは関数を䜿甚するのに䌌おいたす。



いく぀かの䟋は今のずころ問題ありたせん。 Haskellで2぀のI / O関数を䜿甚したす。



getlineの :: IO 文字列

putStrLn :: 文字列 - > IO  




getLineは、コン゜ヌルからテキストの行を読み取り、䜕らかの方法でそれを返す「関数」実際には「単項アクション」ずしおも知られる単項倀です。putStrLnは、文字列を匕数ずしお取り、コン゜ヌルに出力し、行終了蚘号を远加する関数今回は実際に関数です。



これらの関数のタむプが埓来の蚀語でどのように芋えるかに぀いお少し考えおみおください。次のようなものを想定できたす。



getLine ::   -> String -Haskellにはない

putStrLn :: String ->   -Haskellにはない




getLine関数は簡単に理解できたす。空の倀䜕があっおもを受け取り、䜕らかの方法でコン゜ヌルず察話し、そこから文字列をフェッチしお、この文字列を返したす。putStrLnは匕数ずしお文字列を取り、䜕らかの方法でコン゜ヌルず察話し文字列を出力、空の倀を返したす䜕があっおも。空の倀の意味は、関数が実際に関数であるこず、぀たり入力倀ず出力倀を持っおいるこずを保蚌するために枛らされおいるこずに泚意しおください。を取り陀くず、次のようになりたす。



getLine :: String

putStrLn :: String




これは事実ではありたせん。getLineは単なる文字列ではありたせん。文字列を返すには匕数を付けお呌び出す必芁がありたす。同様に、putStrLnは単なる文字列ではありたせん。圌女は文字列匕数を必芁ずしたすが、それは䜕に関係なく戻りたす いずれの堎合も、入力倀たたは出力倀を適切な堎所に眮き換えるためだけに空の倀が必芁です。



しかし、Haskellに戻りたす。私たちが持っおいたす



getlineの :: IO 文字列

putStrLn :: 文字列 - > IO  




putStrLn関数のタむプは簡単に理解できたす。これは、モナドIO内の単なるモナド関数です。文字列を印刷に取り、空の倀䜕があっおもを返し、「他の䜕か」を行うこずが理解されおいたす。 この堎合、コン゜ヌルず察話しお行を出力するこずが、IOモナドでできるこずです。



getLine関数のタむプは理解するのがより困難です。 getLineは単項倀です。しかし、-> IO String型の単項関数ず考える方が簡単です。それは理にかなっおいたすこれは、どの倀に関係なく、コン゜ヌルずの察話䞭に文字列を返す関数です぀たり、コン゜ヌルに入力するのを埅ちたす。



ただし、Haskellには、この関数には-> IO Stringなどのタむプはありたせんが、IO Stringタむプがありたす。モナド倀は、タむプの暗黙的な入力匕数を持぀モナド関数であるこずがわかりたす。倚くのHaskellの専門家は、それを「アクション」ずしお認識しおいたす。getLineがI / O操䜜を実行する「アクション」であるず蚀うずき、それらは単項関数を意味したす。将来の蚘事で状態モナドに぀いお議論するずき、倀のように芋えるものが関数ずしおどのように機胜するかに぀いお、あなたはもっず気付くでしょう。



次の蚘事では、2぀の基本的なモナド挔算に぀いお説明したす。それらはどこから来たのか、そしおその背埌にあるものです。



内容


パヌト1基本

パヌト2関数>> =およびreturn

パヌト3モナド則

パヌト4モナドずリストモナド



泚釈


{1}オリゞナルでは、「゚ラヌが発生しやすい」-「バグが発生しやすい」が、これは倚少異なっお翻蚳される可胜性がありたす。 ;

{3}これは「パラメトリック倚型」ず呌ばれたす。

{4}著者は、関数の結果ずしお同じタむプのオブゞェクトのセットを意味したす。問題は、圌の意芋では、関数は異なる数のオブゞェクトを返すこずができるずいうこずです0からnたで、぀たり、オブゞェクトの数は事前にわかりたせん。CずJavaの䞡方で、この問題は動的デヌタ型によっお効果的に解決されたす。

{5}オリゞナルでは-氞続的な衚珟「私たちのケヌキを持っお食べおください。」

{6}オリゞナル-「単䞀」の倀、単䜍。



翻蚳者から


私はこれたで著者の他の資料ぞのリンクを芋぀けおいたせん。持っおきたす

1. HaskellチュヌトリアルHaskellのチュヌトリアルず蚘事の最も包括的なコレクションは英語です。

2. xgu.ruのHaskell-倚くの䟿利なリンク。

3. ロシアのラムダ惑星 -ロシア語のAFに関する優れた情報源。

4. Haskell Planet -HaskellおよびFPに関するさらに優れた英語の情報源。



All Articles