プログラミングで一般的なファンクター(エンドファンクターに限定されない)の使用法はありますか?[閉まっている]
プログラミングで一般的なファンクター(エンドファンクターに限定されない)の使用法はありますか?
エンドファンクターを採用する理由は、モノイドやモナドのように構造を単純にするためだと理解しています。
また、最終的には、すべての値がプログラミング言語のカテゴリ(Haskなど)に落ち着くことも理解していますが、ここで話しているのは、同じカテゴリの文字列、数値、ブール値、または関数の間のエンドファンクターです。
関連する質問:
すべてのHaskellファンクターはエンドファンクターですか?
ファンクターとエンドファンクターの違い
回答
まず、はい。
たとえば、モノイドは次のような単一オブジェクトカテゴリとして定義できることは誰もが知っています。
- 要素になる矢印
- 単一のオブジェクトには意味がありません
- オペレーターとなる構成(
(<>)Haskell) - id矢印がアイデンティティになる(
memptyHaskellで)。
そして、この意味で、2つのモノイド間の準同型は2つのカテゴリー間の関手になります。
さて、例えば、タイプAしBて、両方ともモノイドです。それらの間のファンクターは、f :: A -> BそれぞれAをBにマップし、構成を保持する準同型関数です。
しかし、待ってください、そうで
f :: A -> BはありませんFunctor(ここでは等幅フォントを使用していることに注意してください)!
いいえ、そうではありませんFunctorHaskellで、それはまだある数学的な意味でファンクタ。
したがって、強調するために、もう一度述べます。「非エンド」ファンクターはプログラミングで使用され、おそらくエンドファンクターよりも頻繁に使用されます。
ここでのポイントは、圏論は非常に抽象的な理論であるということです-それは具体的なオブジェクトを抽象化するための概念を提供します。これらの概念は、さまざまなコンテキストでさまざまなことを意味するように定義できます。
そしてHask(またはセット、またはのサブカテゴリのセット)だけでの1これは作る、これらの無限の定義
- 関数となる矢印
- タイプ(またはセット)になるオブジェクト
- 関数合成となる合成
(.) id関数となるid矢印。
この「カテゴリユニバース」の定義を上記の「カテゴリモノイド」の定義と比較してください。おめでとうございます。カテゴリに対する2つの異なる考え方を知っています。
結論として、圏論自体は単なる抽象概念であることを忘れないでください。抽象化自体には意味がなく、まったく役に立たない。私たちはそれらを本物に接続します、そしてこの方法でのみそれらは私たちに便利さをもたらすことができます。具体的な例を通して抽象的な概念を理解しますが、これらの概念自体を具体的なものに単純化しないでください(たとえば、ファンクターを「カテゴリユニバース」間のファンクターに単純化しないでください(Hask、Setなど)!)。
PS「HaskをHaskellの別のカテゴリに送るファンクターはありますか?」と尋ねた場合。その場合、答えは「はい」または「いいえ」になります。たとえば、カテゴリ定義することができHask * Haskを任意の2種類のデカルトの製品、およびファンクタ含むように
data Diag a = Diag a a、fmap f x = Diag (f x) (f x)それぞれのタイプを送信しA、その広場にしますA * A。しかし、Hask * HaskはまだのサブカテゴリであるHaskので、我々は、これはあまりにもendofunctorであると言うことがあります。
簡単な答え:はい、 Haskellには「小さい」カテゴリがあり、それらの間に(エンドファンクターだけでなく)ファンクターを定義できます。それらが有用かどうかは別の問題です。
これは私が何年もの間疑問に思っていたものです。現在の質問は私にこれを突き刺すように促しました。私は現在、BartoszMilewskiのプログラマーのためのカテゴリー理論を3度目に通過しています。次のことが正しいかどうかわかりませんので、フィードバックをいただければ幸いです。
ハスク
私が正しく理解していれば、Haskは本質的にタイプのカテゴリ(〜セットのカテゴリ)であり、終了しない計算を表すために下部(⊥)がスローされます。これを説明する試みは次のとおりです。
各オブジェクトでHaskは、あるタイプのようにInt、Bool、String、など、独自のカスタムタイプReservation、OrderなどAタイプのように見ることができるセット。たとえば、はBoolを含むセットでTrueありFalse、Stringはすべての文字列のセットなどです。明らかに、これらのセットの多く(などString)は無限です。
さらに、特別なボトムオブジェクトもあります。
タイプを他のタイプにマップすることはできますが、Haskにはすべてのタイプと式が含まれているため、Hask以外のものにマップすることはできません。
ここで私はからのマッピング示されてきたHaskにHaskを複製することによりHaskを、本当に、2つのカテゴリがちょうど2つの同一のイメージです。
ファンクターは、オブジェクトをマッピングするだけでなく、オブジェクト間の射もマッピングするマッピングです。多くすでにこのことについて言われてきた、私はここに作ってあげるので、唯一のポイントは、間ファンクタ以来ということですHaskとHaskは、カテゴリ、彼らしているファンクタ残していない内 Hask、ひいてはendofunctorsを。それFunctorがHaskellの型クラスです。
ユニットカテゴリ
それでは、問題は次のとおりです。Hask内に「より小さな」カテゴリがありますか?
私が知る限り、そうです、無限にたくさんあります。
存在する最も単純なカテゴリの1つは、単一のオブジェクトを持ち、単位元以外の射がないカテゴリです。
Haskellでは、これはユニット(())タイプの写真である可能性があります。ながら()の一部であるHask、あなたも自分自身でカテゴリとしてそれを見ることができます。それをユニットと呼びましょう。
無料のカテゴリ
上記のユニットカテゴリは、無料カテゴリの一例にすぎません。フリーカテゴリは、有向グラフから構築されたカテゴリです。別のグラフは次のとおりです。
これには2つの頂点と2つのエッジがあります。頂点をオブジェクトとして、エッジを射として解釈することにより、このグラフからカテゴリを構築できます。また、各オブジェクトのID射、および射の構成を追加する必要があります。
プログラミングでは、2つのオブジェクトを持つセットは、2人の住民だけを持つタイプと同等です。これらの値にはさまざまな名前を付けることができますが、そのような型は常にと同型Boolです。
ファンクタ
上記の2つのカテゴリ間のマッピングを定義できますか?
はい、ユニットを「より大きな」カテゴリに埋め込むことでこれを行うことができます。これを行うには、オブジェクトの1つを任意に選択します。
他のオブジェクトを選択する別のファンクターが存在します。
これは明らかにカテゴリ間のマッピングであるため、エンドファンクターではありません。しかし、それは適切なファンクターですか?
ファンクターになるためには、マッピングはオブジェクトをオブジェクトにマッピングするだけでなく、射を射にマッピングする必要があります。ユニットにはアイデンティティ射しかないため、これはここでも当てはまります。したがって、選択したターゲットオブジェクトの単位射に単位射をマッピングします。で可能な唯一の組成物ユニットがありid ∘ id、id ∘ id ∘ idなど。これらはすべてにマップid ∘ id、id ∘ id ∘ idターゲットオブジェクトの上に、など。
圏論に手を出しているのはほんの数年ですが、これは適切な関手だと思います。
Haskellカテゴリ型クラス
HaskellはCategoryと呼ばれる型クラスを定義しています。これはかなりの上に適合しない単位のカテゴリ、またはそれを想定しているので、自由なカテゴリの例の上に、それはCategoryより高いkindedタイプ(すなわち、それが含むことである種類の中)Hask。それでも、ユニットと上記の無料カテゴリを靴べらに入れCategoryて、それからファンクターを作成できるかどうかを見てみましょう。
単位としてCategory
のインスタンスはCategoryより種類の多いタイプ(つまりcat a b)である必要があるため()、Categoryインスタンスに変えることはできません。ただし、同型のより種類の多い型を定義することはできます。
data U a b = U deriving (Eq, Show)
Constファンクターと同様に、この型は型変数を定義し、それを無視します。と同様()に、U型には値が1つだけあり、U。とも呼ばれます。(演習:ことを示しているUと()同型です。)
私たちは、作ることができるインスタンスを:UCategory
instance Category U where
id = U
U . U = U
しかし、それは適切なカテゴリーですか?それは法律に従いますか?
等式推論を使用して、それが機能することを証明できます。
正しいアイデンティティ
U . id
= { definition of (.) }
U
左のアイデンティティ
id . U
= { definition of (.) }
U
結合性
U . (U . U)
= { definition of (.) }
U . U
= { redundant brackets }
(U . U)
= { definition of (.) }
(U . U) . U
それは私には良さそうです。
自由圏の例 Category
上記の無料カテゴリの例はどうですか?上記のUタイプのように、この小さなカテゴリをパラメトリックに多形にすることはできませんが、ファントムタイプを定義することはできます。
data Bendo a b = Bendo { runB :: Bool -> Bool }
other :: Bendo a b
other = Bendo not
私はタイプと呼ばきたBendoためブール自己準同型それはそれがあることが判明したものですので、。2つのオブジェクト(TrueとFalse)の間のエッジは、他のオブジェクトの選択に対応します。これは、組み込みnot関数と同等です。
問題のカテゴリをモデル化するにはother、許可される射はとだけなidので、他の関数Bool -> Bool(など\_ -> True)は許可しないでください。したがって、定義するモジュールBendoはデータコンストラクターをエクスポートするべきではありません。
我々は作ることができインスタンスを?BendoCategory
instance Category Bendo where
id = Bendo id
(Bendo f) . (Bendo g) = Bendo (f . g)
確かに、これは可能です。これがカテゴリであることを証明するつもりはありません。これは、実際にはに->特化したカテゴリインスタンスにすぎないため(->) Bool Boolです。
ファンクタ
Uとの間のファンクターを定義しましょうBendo。これを行うには、Control.Categorical.FunctorでFunctor指定されているより一般的な定義を使用できます。このすべてを機能させるには、次のような通常の定義を非表示にする必要があります。Prelude
import Control.Category
import Control.Categorical.Functor
import Prelude hiding (id, (.), Functor(..))
また、サポートする必要がありますMultiParamTypeClasses:
{-#LANGUAGE MultiParamTypeClasses #-}
そのより一般的なFunctor型クラスを実装するには、より種類の多い型が必要です。繰り返しますが、目的のために別のファントムタイプを作成しましょう。
data Embed a = Embed deriving (Eq, Show)
これは、インスタンスを定義するのに十分です。
instance Functor Embed U Bendo where
fmap U = Bendo id
これはU、の恒等写像にマッピングされBendoます。
使用するのは少し厄介ですが、それは可能です:
> (runB $ (fmap U :: Bendo (Embed a) (Embed b))) False False > (runB $ (fmap U :: Bendo (Embed a) (Embed b))) True
True
Haskellはタイプがどうなるか理解できないfmap Uので、あなたはそれを言わなければなりません。結果のタイプがBendo (Embed a) (Embed b)、である必要があることを伝えると、アイデンティティの射にfmapマップUされます。これrunBは、Trueまたはのいずれかに適用することで確認できますFalse。
結論
プログラミングには(エンドファンクターだけでなく)ファンクターが存在しますか?はい、彼らはやる。
それらは役に立ちますか?少し目を細めてみると、これらのファンクターは「通常の」関数のサブセットにすぎないように思われます。上記のファンクターの簡略版は次のとおりです。
uToBendo :: () -> Bool -> Bool
uToBendo () = id
これは単なる正常な機能です。
このように見たときに、もっと便利なアプリケーションがあるかどうかをもっと考えなければなりません。