ファンクタヌ「プログラマヌ向けのカテゎリヌ理論」の本の章

これは、プログラマシリヌズのカテゎリ理論の7番目の蚘事です。 以前の蚘事はすでにHabréで公開されおいたす。



ファンクタヌ


ファンクタヌの抂念の背埌には、非垞にシンプルでありながら匷力なアむデアがありたすどのようにハックされおいるように聞こえおも。 単なるカテゎリヌ理論は、シンプルで匷力なアむデアに満ちおいたす。 ファンクタヌは、カテゎリヌ間のマッピングです。 2぀のカテゎリCずDが䞎えられ、ファンクタヌFがCのオブゞェクトをDのオブゞェクトにマッピングするずしたす-これはオブゞェクトに察する関数です。 aがCからのオブゞェクトである堎合、 Dからの画像をF a 括匧なしで瀺したす。 ただし、カテゎリはオブゞェクトだけでなく、それらを぀なぐ射でもありたす。 ファンクタは射も衚瀺したす-これは射に察する関数です。 しかし、射はランダムに衚瀺されるのではなく、接続を維持するような方法で衚瀺されたす。 ぀たり、Cの射fがオブゞェクトaずオブゞェクトbを関連付ける堎合、


f :: a -> b 

次に、Dのfの画像F fは 、 aの画像ずbの画像を接続したす。


 F f :: F a -> F b 

数孊衚蚘ずHaskell構文のこのような混合物が読者に理解できるこずを願っおいたす。オブゞェクトたたは射にファンクタヌを適甚するこずで括匧を曞きたせん。



ご芧のように、ファンクタヌは構造を保持したす。入力カテゎリで接続されおいたものは、出力でも接続されたす。 しかし、構造はこれに限定されたせん射の合成をサポヌトするこずも必芁です。 hがfずg合成でf g 


次に、Fの䜜甚䞋の画像が画像fずgの合成であるこずが必芁です。


 F h = F g . F f 


最埌に、Cからのすべおのナニット同䞀性射がDからのナニット射にマッピングされる必芁がありたす。


 F id(a) = id(F a) 

ここで、 id aはオブゞェクトaの単䜍射であり、 id F aはオブゞェクトF aの単䜍射です。



これらの条件はすべお、射ずしお適した関数の範囲を倧幅に制限するこずに泚意しおください。 ファンクタヌは、カテゎリヌの構造を維持する必芁がありたす。 カテゎリヌを射ず混ざり合ったオブゞェクトのセットずしお想像するず、ファンクタヌはこのレヌスの単䞀の糞を切る暩利を持ちたせん。 耇数のオブゞェクトを組み合わせるこずができ、モヌフィズムを1぀に結び付けるこずができたすが、結び付きを壊すこずはありたせん。 この制限は、数孊的分析の連続性の抂念に䌌おいたす。 この意味で、ファンクタヌは「連続的」ですただし、ファンクタヌの連続性にはさらに制限的な定矩がありたす。 他の関数ず同様に、ファンクタヌは接着たたはネストできたす。 投資の偎面は、゜ヌスカテゎリがタヌゲットよりもはるかに小さいずきに最も顕著になりたす。 極端な堎合、最初のカテゎリはカテゎリ1で、1぀のオブゞェクトず1぀の単䞀の射で構成されたす。 カテゎリ1から他のカテゎリぞのファンクタは、このカテゎリから特定のオブゞェクトを遞択するだけです。 タヌゲットセットから芁玠を遞択するシングルトン射ずの完党な類䌌性がありたす。 䞍合理に枛少した接着面は、定数ファンクタヌΔcで芳察されたす 。 ゜ヌスカテゎリの各オブゞェクトをタヌゲットカテゎリの特定のオブゞェクトcにマップし、すべおの射を単䞀の射ID id cにマップしたす。 それはブラックホヌルのようなもので、すべおを特異点に吞い蟌みたす。 制限ず共同制限に぀いお議論するずき、このファンクタヌの考察に戻りたす。


プログラミングのファンクタヌ

私たちは地球、プログラミングの䞖界に戻りたす。 したがっお、型ず関数のカテゎリがありたす。 このカテゎリヌを自分自身にマップするファンクタヌ、いわゆる゚ンドファンクタヌを考えおください。 型カテゎリの内機胜ずは䜕ですか たず、あるタむプを別のタむプにマップしたす。 実際、私たちはそのようなマッピングに粟通しおいたす;これらは他の型によっおパラメヌタ化された型です。 いく぀かの䟋を芋おみたしょう。


たぶんファンクタヌ

Maybeの定矩は、タむプaからMaybe aぞのマッピングです。


 data Maybe a = Nothing | Just a 

重芁な詳现 Maybeそれ自䜓は型ではなく、型コンストラクタです。 IntやBoolなどの型を匕数ずしお受け取り、別の型を返したす。 Maybe 、匕数なしは型に関する関数です。 しかし、 Maybeファンクタヌでしょうか 以䞋、プログラミングの文脈でファンクタヌに぀いお話すずき、゚ンドファンクタヌはほずんど垞に意味されたす。結局、ファンクタヌはオブゞェクトここでは型のマッピングだけでなく、射ここでは関数のマッピングでもありたす。 aからbたでのすべおの関数


 f :: a -> b 

Maybe bからMaybe bたでの関数を取埗したいず思いたす。 このような関数を定矩するには、2぀のMaybeコンストラクタヌに察応する2぀のケヌスを考慮する必芁がありたす。 Nothingの堎合、単玔にNothing返したす。 匕数がJust堎合、関数fをそのコンテンツに適甚したす。 そのため、 Maybeの圱響䞋にあるfのむメヌゞは関数です


 f' :: Maybe a -> Maybe b f' Nothing = Nothing f' (Just x) = Just (fx) 

ずころで、Haskellでは、倉数名にアポストロフィを䜿甚できたす。これは、このような堎合に非垞に䟿利です。Haskellでは、モヌフィズムの衚瀺を担圓するファンクタヌの倖芳は、高次fmapによっお実装されたす。 Maybe次のシグネチャがありたす。


 fmap :: (a -> b) -> (Maybe a -> Maybe b) 


fmapは関数を䞊げる持ち䞊げるずよく蚀われたす。 sublime関数は、 Maybe倀で機胜したす。 通垞、カリヌ化により、このシグニチャは2぀の方法で解釈できたす。1぀の倉数の関数ずしお、それ自䜓が関数(a->b)であり、関数を返す(Maybe a -> Maybe b) (a->b) (Maybe a -> Maybe b) 、たたは2぀の倉数の関数ずしお、 Maybe bを返したす


 fmap :: (a -> b) -> Maybe a -> Maybe b 

䞊蚘に埓っお、 Maybe fmapを定矩したす。


 fmap _ Nothing = Nothing fmap f (Just x) = Just (fx) 

Maybe型コンストラクタヌずfmap関数がファンクタヌを構成しおいるこずを瀺すために、 fmapナニットモヌフィズムず合成を保持するこずを蚌明する必芁がありたす。 これらの声明は「機胜法」ず呌ばれたすが、カテゎリの構造が保持されおいるこずを単に蚌明するものです。


同等の倉換方法

Haskellの兞型的な蚌明手法である等䟡倉換の方法により 、関数法則を蚌明したす。 このメ゜ッドは、Haskellの関数が等匏のセットによっお定矩されおいるずいう事実に䟝存しおいたす巊偎は右偎に等しく、䞡方を盞互に眮き換えるこずができたす競合を避けるために眮換するずきに倉数の名前を倉曎する必芁がある堎合がありたす。 呌び出しの代わりに関数本䜓を眮き換えるむンラむン化か、本䜓の代わりに関数を呌び出すリファクタリングこずができたす。 䟋ずしお恒等関数を考えたす


 id x = x 

どこかで、たずえばid yに出䌚えば、い぀でもy むンラむン化に眮き換えるこずができたす。 䞀般に、匏id (y + 2)などid (y + 2)に適甚されるid出珟は、この匏(y + 2)眮き換えるこずができたす。 逆方向匏eはid e リファクタリングに眮き換えるこずができたす。 パタヌンマッチングによっお定矩された関数の堎合、各定矩を個別に䜿甚できたす。 たずえば、䞊蚘のfmap定矩に埓っお、 fmap f NothingをNothingたたはその逆に眮き換えるこずができたす。 このアプロヌチを実際に怜蚎しおください。 アむデンティティを維持するこずから始めたしょう


 fmap id = id 

NothingずJust 2぀のケヌスを怜蚎する必芁がありたす。 Nothingから始めたしょう擬䌌Haskellを䜿甚しお、等匏の巊偎から右偎ぞの倉換に぀いお説明したす。


  fmap id Nothing = {   fmap } Nothing = {   id } id Nothing 

2番目のステップで、反察方向のidの定矩を䜿甚しお、 id Nothing代わりにid Nothingを眮き換えたこずに泚意しおください。 実際には、このような蚌拠は、「この堎合はNothingずいう同じ衚珟で䌚議が真ん䞭になるたで、「䞡端から芯を燃やす」ずいう方法によっお行われたす。 2番目のケヌスも簡単です。


  fmap id (Just x) = {   fmap } Just (id x) = {   id } Just x = {   id } id (Just x) 

fmapがコンポゞションを保存するこずを瀺したす


 fmap (g . f) = fmap g . fmap f 

Nothingケヌスから始めたしょう。


  fmap (g . f) Nothing = {   fmap } Nothing = {   fmap } fmap g Nothing = {   fmap } fmap g (fmap f Nothing) 

それではJustの時間です。


  fmap (g . f) (Just x) = {   fmap } Just ((g . f) x) = {    } Just (g (fx)) = {   fmap } fmap g (Just (fx)) = {   fmap } fmap g (fmap f (Just x)) = {    } (fmap g . fmap f) (Just x) 

C ++スタむルの副䜜甚を持぀関数では、同等の倉換方法が機胜しないこずを匷調する䟡倀がありたす。 䟋を考えおみたしょう


 int square(int x) { return x * x; } int counter() { static int c = 0; return c++; } double y = square(counter()); 

同等の倉換方法では、 squareを展開しお取埗できたす


 double y = counter() * counter(); 

間違いなく、そのような倉換は正しくなく、匏の結果を倉曎したす。 それにもかかわらず、 squareマクロずしお定矩されおいる堎合、C ++プリプロセッサヌは同等の倉換方法を䜿甚しお、悲惚な結果をもたらしたす。


たぶんたた

ファンクタはHaskellで簡単に衚珟できたすが、䞀般化プログラミングず高階関数をサポヌトする任意の蚀語で蚘述するこずができたす。 optionalのテンプレヌトタむプであるMaybeのC ++アナログを考えおみたしょう。 以䞋に実装のスケッチを瀺したす完党な実装は、匕数を枡すさたざたな方法、コピヌセマンティクス、およびC ++リ゜ヌス管理に固有のその他の問題を明瀺的に説明しおいるため、はるかに耇雑です。


 template<class T> class optional { bool _isValid; // the tag T _v; public: optional() : _isValid(false) {} // Nothing optional(T x) : _isValid(true) , _v(x) {} // Just bool isValid() const { return _isValid; } T val() const { return _v; } }; 

䞊蚘のテンプレヌトは、ファンクタヌの説明の半分であるタむプマッピングを提䟛したす。 新しいタむプのoptional<T>各タむプTにマップしたすT 次に、関数に察するアクションを説明したす。


 template<class A, class B> std::function<optional<B>(optional<A>)> fmap(std::function<B(A)> f) { return [f](optional<A> opt) { if (!opt.isValid()) return optional<B>{}; else return optional<B>{ f(opt.val()) }; }; } 

これは、関数を匕数ずしお受け取り、関数を返す高階関数です。 そしお、カレヌなしの別のオプションがありたす


 template<class A, class B> optional<B> fmap(std::function<B(A)> f, optional<A> opt) { if (!opt.isValid()) return optional<B>{}; else return optional<B>{ f(opt.val()) }; } 

たたは、 optionalテンプレヌトメ゜ッドずしおfmapを実装できたす。 このような遞択のあいたいさにより、C ++の「ファンクタヌ」パタヌンの抜象化が問題になりたす。 ファンクタを継承するには、ファンクタをむンタヌフェヌスにする必芁がありたす残念ながら、テンプレヌト関数は仮想化できたせん。 それずも、無料のテンプレヌト関数、カレヌかどうか C ++コンパむラは欠萜しおいる型を正しく掚枬できたすか、たたは明瀺的に蚭定する必芁がありたすか 入力関数fがintをbool倉換するず想像しおください。 コンパむラヌがタむプg決定する方法


 auto g = fmap(f); 

特に将来、 fmapバヌゞョンで倚くのファンクタヌが存圚する堎合は 他のタむプのファンクタヌに぀いおはすぐに知るこずができたす。


型クラス

ファンクタの抜象化はHaskellでどのように実装されおいたすか 型クラスのメカニズムが䜿甚されたす。 型クラスは、単䞀のむンタヌフェヌスをサポヌトする型のファミリヌを定矩したす。 たずえば、同等性に匹敵するオブゞェクトのクラスは次のように定矩されたす。


 class Eq a where (==) :: a -> a -> Bool 

型a 2぀の匕数を取り、 Boolを返す挔算子(==)サポヌトする堎合、型aはクラスEqに属するず䞻匵したす。 特定の型がEqに関連しおいるこずをHaskellに玍埗させるには、クラスのむンスタンス むンスタンス、実装ずしお宣蚀し、実装(==)を提䟛する必芁がありたす。 たずえば、そのような平面䞊の点の定矩2぀のFloat型積


 data Point = Pt Float Float 

点の等䟡性を刀断するこずが可胜です


 instance Eq Point where (Pt xy) == (Pt x' y') = x == x' && y == y' 

ここで、定矩された挔算子(==)は、2぀のパタヌン(Pt xy)ず(Pt x' y')間に挿入されおいたす。 関数の本䜓は=蚘号の右偎に配眮されたす。 Point Eqむンスタンスずしお宣蚀された埌、 Point等しいかどうかを盎接比范できたす。 C ++やJavaずは異なり、 Pointを定矩するずきにクラスやEqむンタヌフェむスを提䟛する必芁はないこずに泚意しおください-これは埌で行うこずができたす。 Haskellで関数および挔算子をオヌバヌロヌドするためのメカニズムは、型クラスだけであるこずに泚意しおください。 さたざたなファンクタヌのfmapをオヌバヌロヌドするために必芁です。 埮劙な点が1぀ありたす。ファンクタは型ずしおではなく、型に察する関数、型コンストラクタずしお定矩されたす。 型クラスは、 Eqの堎合のように、型だけでなく、型コンストラクタのファミリヌを蚘述する必芁がありたす。 幞いなこずに、Haskellの型クラスメカニズムは単玔な型だけでなく型コンストラクタヌでも機胜したす PP関数型パラダむムに埓う良い䟋-関数型の䞖界においおも、オブゞェクトより悪くはありたせん 。 Functorクラスの定矩は次のずおりです。


 class Functor f where fmap :: (a -> b) -> fa -> fb 

䞎えられた眲名を持぀fmap関数がある堎合、 fはFunctorであるず䞻匵したす。 ここで、 fはmであり、 m ず同じ皮類の新しい倉数ず、新しい倉数aおよびbです。 しかし、コンパむラはfが型コンストラクタであるこずを理解でき、その䜿甚を远跡したす。他の型、ここではfaおよびfb適甚したす。 したがっお、Maybeの堎合のように、ファンクタヌのむンスタンスずしお宣蚀するのは型コンストラクタヌです。


 instance Functor Maybe where fmap _ Nothing = Nothing fmap f (Just x) = Just (fx) 

Functorクラスず、むンスタンスMaybeを含む倚くの䞀般的な型の宣蚀がPrelude暙準ラむブラリに含たれおいるこずに泚意しおください。


C ++のファンクタヌ

C ++で同じアプロヌチを適甚できたすか 型コンストラクタはoptionalなどのテンプレヌトクラスに察応するため、テンプレヌトパラメヌタFを䜿甚しおfmap 2回パラメヌタ化する必芁がありたすF 次のように曞かれおいたす。


 template<template<class> F, class A, class B> F<B> fmap(std::function<B(A)>, F<A>); 

しかし、このテンプレヌトをさたざたなファンクタヌに特化するにはどうすればよいでしょうか 残念ながら、C ++テンプレヌト関数の郚分的な特殊化は犁止されおいたす。 あなたは曞くこずができたせん


 template<class A, class B> optional<B> fmap<optional>(std::function<B(A)> f, optional<A> opt) 

代わりに、関数のオヌバヌロヌドに戻る必芁がありたす。その結果、 fmapの元の定矩に戻りたすカリヌ化せずに。


 template<class A, class B> optional<B> fmap(std::function<B(A)> f, optional<A> opt) { if (!opt.isValid()) return optional<B>{}; else return optional<B>{ f(opt.val()) }; } 

この定矩は機胜したすが、適切なオヌバヌロヌドを行うには2番目の匕数が必芁です。 fmapのより䞀般的な定矩fmap単に無芖されたす。


ファンクタヌリスト

プログラミングにおけるファンクタヌの重芁性をよりよく理解するには、さらに䟋を怜蚎しおください。 別の型によっおパラメヌタヌ化された型は、ファンクタヌの圹割の候補です。 たずえば、䞀般化されたコンテナは、芁玠のタむプによっおパラメヌタ化されたす;リスト、非垞に単玔なコンテナを考えおください


 data List a = Nil | Cons a (List a) 

ここには、 List型コンストラクタがありたす。これは、任意の型aからList aぞのマッピングです。 Listがファンクタヌであるこずを瀺すために、ファンクタヌに沿った関数のリフティングを定矩する必芁がありたす。 特定の関数a->b List a -> List b a->b List a -> List b a->b定矩したす。


 fmap :: (a -> b) -> (List a -> List b) 

List機胜する関数は、2぀のリストコンストラクタヌに぀いお、それぞれ2぀のケヌスを考慮する必芁がありたす。 Nilの堎合は些现なこずですNilが返されたす。空のリストから倚くを絞り出すこずはできたせん。 Consケヌスは、再垰に圱響するため、 Consにくいです。 考えおみたしょう。したがっお、リストa 、関数fがaをbに倉換し、リストbを取埗したいずしたす。 圓然、 fを䜿甚しお各リスト項目をaからbに倉換する必芁がありたす。 空でないリストが頭ず尟のConsずしお定矩されおいる堎合、正確に䜕をする必芁がありたすか fを頭に適甚し、隆起したfmapで欠けた fを尟に適甚したす。 この定矩は再垰的です。raisedfからraised fたでを定矩したす。


 fmap f (Cons xt) = Cons (fx) (fmap ft) 

fmap fの右偎で、 fmap fが定矩したものよりも短いリスト、぀たり埌者の末尟に適甚されるこずが重芁です。 より短いリストに再垰を適甚するため、必然的に空のリスト、たたはNilたす。 しかし、すでに決定したように、 Nil fmap fはNilを䞎え、それにより再垰を完了したす。 Consコンストラクタヌを䜿甚しお、新しいヘッド fx ず新しいテヌル fmap ft を組み合わせるこずにより、最終結果が埗られたす。 その結果、ファンクタのむンスタンスずしおのリストの完党な宣蚀は次のずおりです。


 instance Functor List where fmap _ Nil = Nil fmap f (Cons xt) = Cons (fx) (fmap ft) 

C ++に慣れおいる堎合は、 std::vectorを怜蚎するのが理にかなっおいたす。これは基本的に基本的なC ++コンテナヌです。 std::vectorのfmap実装は、 std::transform単なるラッパヌです


 template<class A, class B> std::vector<B> fmap(std::function<B(A)> f, std::vector<A> v) { std::vector<B> w; std::transform( std::begin(v) , std::end(v) , std::back_inserter(w) , f); return w; } 

その助けを借りお、たずえば、䞀連の数字を2乗するこずができたす。


 std::vector<int> v{ 1, 2, 3, 4 }; auto w = fmap([](int i) { return i*i; }, v); std::copy( std::begin(w) , std::end(w) , std::ostream_iterator(std::cout, ", ")); 

ほずんどのC ++コンテナヌは、本質的にファンクタヌです。 これは、 fmapプリミティブな盞察であるstd::transform枡すこずができる反埩子の存圚によっお保蚌されたす。 残念ながら、ファンクタヌの単玔さは、むテレヌタヌず䞀時倉数䞊蚘のfmap実装のようにのゎミの䞋で倱われたす。 良いニュヌスから-C ++に含める予定の範囲のラむブラリは、その間隔、機胜的な性質を倧幅に明らかにしたす。


リヌダヌファンクタヌ

ある皮の盎芳、特にファンクタが䜕らかのコンテナであるずいうこずを開発したので、ここでは䞀芋完党に異なる䟋です。 タむプaからaを返す関数のタむプぞのマッピングを怜蚎しおください。 適切な理論レベルおよびカテゎリレベルでの機胜タむプの議論にはただ到達しおいたせんが、プログラマずしお、それらに぀いおある皋床理解しおいたす。 Haskellでは、関数型は、型コンストラクタヌである矢印(->)を䜿甚しお構築されたす。矢印(->)は、匕数型ず結果型の2぀の型を取りたす。 既に䞭眮蚘法a->bでそれを満たしおいるが、括匧を䜿甚するず接頭蟞蚘法も䜿甚できたす。


 (->) ab 

通垞の関数ず同様に、m およびいく぀かの匕数の新しい関数を郚分的に適甚できたす。 そしお、矢印に1぀の匕数を䞎えたずき、ただ別の匕数を埅っおいたす。 ぀たり、


 (->) a 

型コンストラクタです。 本栌的なタむプa->bを取埗するには、もう1぀のタむプbが必芁です。 したがっお、矢印は、によっおパラメヌタ化されaタむプコンストラクタヌのファミリ党䜓を定矩したす。 ファンクタのファミリヌでもあるかどうかを調べおみたしょう。 2぀のパラメヌタヌを混同しないように、それらの名前を倉曎しお、圹割を匷調したす。 ファンクタヌの以前の定矩に埓っお、匕数の型はrず呌ばれ、結果の型はaです。 したがっお、コンストラクタヌは任意のタむプのa取り、タむプr->aマップしたす。 機胜を正圓化するために、関数a->bをr->aを受け取りr->bを返す関数に䞊げる必芁がありたす。 これらはbそれぞれbずbのコンストラクタアクション(->) rによっお䜜成されるタむプです。 これは眲名fmapです


 fmap :: (a -> b) -> (r -> a) -> (r -> b) 

関数f::a->bず関数g::r->a 、 r->b䜜成するg::r->aパズルのようなものが埗られたす。 それらを構成する方法は1぀しかなく、結果はたさに必芁なものです。 このようなfmap実装が刀明したす。


 instance Functor ((->) r) where fmap fg = f . g 

うたくいきたした ミニマリストは、プレフィックス圢匏を䜿甚しおレコヌドを短瞮できたす。


 fmap fg = (.) fg 

匕数を省略しお、2぀の関数を識別できるようになりたした。


 fmap = (.) 

型コンストラクタ(->) rずfmapこのような実装の組み合わせは、「リヌダヌ」ず呌ばれたす。


コンテナずしおのファンクタヌ

プログラミングでファンクタヌを䜿甚しお汎甚コンテナヌを定矩する䟋、たたは少なくずもファンクタヌをパラメヌタヌ化する型の倀を含むオブゞェクトを定矩する䟋に぀いお知りたした。 関数をデヌタずは考えおいないため、リヌダヌファンクタヌは䟋倖のようです。 ただし、これたで芋おきたように、蚈算がテヌブルの怜玢に限定される堎合、メモ化は関数に適甚できたす。 テヌブルはすでにデヌタです。 䞀方、Haskellは遅延しおいるため、リストのような埓来のコンテナヌは実際には関数ずしお実装できたす。 たずえば、次のように説明できる自然数の無限リストを芋おください。


 nats :: [Integer] nats = [1..] 

最初の行の角括匧のペアは、リスト甚の組み蟌みt および新しいHaskellコンストラクタヌです。 2行目では、括匧を䜿甚しおリストリテラルを圢成したす。 明らかに、メモリ内にこのような無限のリストを配眮するこずは䞍可胜です。 代わりに、コンパむラは芁求に応じお敎数を生成する関数を䜜成したす。 Haskell : , , . , , , . strlen , . , . , , , , ! ( ) ( ), . C++, — std::future , - , ; , , , . IO Haskell, , “Hello World!” . , , , . . , , — . , — . , — , , , , . , , , a :


 data Const ca = Const c 

Const , c a . , , , (->) .


 fmap :: (a -> b) -> Const ca -> Const cb 

, fmap , — :


 instance Functor (Const c) where fmap _ (Const v) = Const v 

C++ ( , !), , , , .


 template<class C, class A> struct Const { Const(C v) : _v(v) {} C _v; }; 

C++ - fmap , Const , .


 template<class C, class A, class B> Const<C, B> fmap(std::function<B(A)> f, Const<C, A> c) { return Const<C, B>{c._v}; } 

, Const . Δ c , — . .



, , . , , , . , , . . , . maybeTail ( : )? , Haskell:


 maybeTail :: [a] -> Maybe [a] maybeTail [] = Nothing maybeTail (x:xs) = Just xs 

( , Nil [] . Cons : ().) maybeTail , Maybe [] , a . fmap , f : Maybe list ? . fmap , Maybe . f Maybe , f . ( fmap f ), . , Maybe list :


 square x = x * x mis :: Maybe [Int] mis = Just [1, 2, 3] mis2 = fmap (fmap square) mis 

, , fmap Maybe , , — list . , , :


 mis2 = (fmap . fmap) square mis 

, fmap :


 fmap :: (a -> b) -> (fa -> fb) 

, fmap (fmap . fmap)


 square :: Int -> Int 


 [Int] -> [Int] 

fmap


 Maybe [Int] -> Maybe [Int] 

mis . , , fmap fmap . : , ( , ). , , , . , . ? , , . . , , . , Cat ( , ). "" , , -, , . , "". , , , . , .


挔習

  1. `Maybe` ,
    fmap _ _ = Nothing
    ? (: )
  2. `reader` (: ).
  3. reader (, , Haskell).
  4. . , ( ).

謝蟞

. .
leshabirukov : Bodigrim , . .



Source: https://habr.com/ru/post/J305018/


All Articles