米田の補題
-
1
ななしのよっしん
2019/06/29(土) 09:11:48 ID: 0a32yuiYB8
-
分離乙です
-
👍0高評価👎0低評価
-
2
ななしのよっしん
2020/03/18(水) 06:50:02 ID: 0a32yuiYB8
-
👍0高評価👎0低評価
-
3
ななしのよっしん
2021/02/07(日) 10:52:33 ID: JZq4TJ1Hx/
-
👍0高評価👎0低評価
-
4
ななしのよっしん
2021/05/18(火) 02:26:32 ID: vV4BLHkd1O
-
だいぶ迷走してるな
関数型言語やOperationalモナドの文脈で米田の補題で語るなら、Coyonedaは任意の * -> * を関手に持ちあげられるというだけなので一旦Operationalモナドを切り離して考えた方がいい
fmapの定義がこれ
fmap :: (a -> b) -> f a -> f b
で、これは下のように変形できる
fmap :: ((a -> b), f a) -> f b
つまり、a -> bとf aの組からf bを作れるものがファンクタというわけだ
ところで、Coyonedaの定義は以下だった
CoYoneda f a = (f x, x -> a)
これはx -> aとf xの組からCoyonedaを構成すると言っているのだから、Coyonedaは単にfmapを代数的データ型で表したものといえる。これが関手を実装できるのはごく当然だろう
ここから、Coyonedaのことを自由関手と呼ぶ -
👍0高評価👎0低評価
-
5
ななしのよっしん
2021/05/18(火) 02:27:37 ID: vV4BLHkd1O
-
ここからOperationalモナドの話(つまり蛇足)
Freeモナドは任意の関手をモナドに持ちあげられるものだが、その定義は以下
Free f a where
Pure :: a -> Free f a
Join :: f (Free f a) -> Free f a
で、モナドの定義はこれ
class Monad m where
pure :: a -> m a
(>>=) :: m a -> (a -> m b) -> m b
CoyonedaとFunctorの関係と、Freeとモナドの関係は見るからにそっくりで、同様の理屈でFreeはモナドを実装する
Freeは自由モナドと呼ばれる
この二つを積み上げると、f :: * -> * からモナドを構成できるようになる
type M f = Free (Coyoneda f)
Mは自由モナドであるから、好きなようにアクション(Haskell上で、戻り値の型がm aであるような関数)を作成し、後から"実行"することができる -
👍0高評価👎0低評価
-
6
ななしのよっしん
2021/05/18(火) 02:34:04 ID: vV4BLHkd1O
-
ここからOperationalモナドが何の役に立つのか(つまり蛇足の蛇足)
下のようにget, putというのアクションを予め用意しておいて、
data Sample a where
Get :: Sample String
Put :: String -> Sample ()
type SampleM = M Sample
get :: SampleM String
get = toM Get
put :: String -> SampleM ()
put = toM . Put
自由モナドを"実行"する時にそのアクションの振る舞いを決める(構造を"潰す")ことができる
runSampleM :: SampleM a -> IO a
runSampleM (Pure a) = pure a
runSampleM (Join (Coyoneda f Get)) = getContents >>= runSampleM . f
runSampleM (Join (Coyoneda f (Put s)) = putStrLn s >>= runSampleM . f
予めアクション(operations)を用意しておけることから、Operationalモナドと呼ばれている -
👍0高評価👎0低評価
-
7
ななしのよっしん
2021/05/19(水) 20:29:23 ID: fumz9DZAK9
-
>>4
分割前の記事に書き始めてから4年余り。ようやく分かっている人にめぐりあえました。
これを逃すと4年後まで誰も現れないかもしれないので、色々ご教授願えませんでしょうか。
ひとまず>>4について、以前から分からなかった点があるのですが、
1つ目:
> fmapの定義がこれ
> fmap :: (a -> b) -> f a -> f b
ということなのですが、これは関数の型を定義しているだけで、実装の定義ではないと思うのですが、実装の定義はどこにあるのでしょうか?
2つ目:
CoYoneda f a = (f x, x -> a)のxは何なんでしょうか?
記事で、CoYoneda f a x = f x -> (x -> a)として、
CoYoneda f a = x -> f x -> (x -> a)までは当時わかっていたと思うのですが、どうしても上記までつなげることが出来ませんでした。 -
👍0高評価👎0低評価
-
8
ななしのよっしん
2021/05/23(日) 02:45:21 ID: vV4BLHkd1O
-
>>7
好き勝手書いておいて返事が遅くなって申し訳ないです。
1. fmapの実装
ここでは「fmap :: (a -> b) -> f a -> f bという関数を持つ構造をファンクタと呼ぶ」ということが定義されているのであり、fmapが具体的にどのような関数であるかはそのファンクタの具体的な構造に依ります。
例えばListファンクタのfmapは「fmap :: (a -> b) -> List a -> List b」という型になり、この関数の意味するところは「a -> b」という関数を「List a -> List b」という関数に"持ち上げる"ということになります。
Listの場合、その振舞いは下のようになるのが自然でしょう。
>>> fmap (* 2) ([1,2,3])
[2,4,6]
ファンクタの数だけfmapの実装があるのであり、ファンクタに一般的なfmapの実装があるわけではありません。
2. Coyoneda f a = (f x, x -> a)のx
上のxは全称量化された型です。省略せずに書くと、
Coyoneda f a = ∀x. (f x, x -> a)
ということです。
日本語で書けば、「全てのxに対して、f xとx -> aのペアはCoyoneda f aを構成する」というような感じです。
下の二つは少し正しいとはいいがたいです。
* Coyoneda f a x = f x -> (x -> a)
* Coyoneda f a = x -> f x -> (x -> a)
前者は、全称量化のニュアンスが消えています。
後者は、余計な要素xが増えています。
後者を日本語で書くと、「全てのxに対して、xとf xとx -> aのペアはCoyoneda f aを構成する」となってしまっています。
-
👍0高評価👎0低評価
-
9
ななしのよっしん
2021/05/23(日) 02:49:21 ID: vV4BLHkd1O
-
👍0高評価👎0低評価
-
10
ななしのよっしん
2021/05/23(日) 02:51:42 ID: vV4BLHkd1O
-
👍0高評価👎0低評価
-
11
ななしのよっしん
2021/05/23(日) 06:40:16 ID: fumz9DZAK9
-
理解が行き届かない質問にお答え下さりありがとうございます。もうしばらくお付き合い願えれば幸いです。
>>8-1
> ファンクタの数だけfmapの実装があるのであり、ファンクタに一般的なfmapの実装があるわけではありません。
Coyonedaを用いると、任意の型クラスfからfmapの実装が導き出せる
もしくは米田の補題の証明に出てくる何かがfmapの実装になっている
ということだと思っているのですが、
もしかして米田の補題はfに対応するfmapの「存在」を証明しているだけで、実装を導き出すことは出来ないのでしょうか。
>>8-2
> 下の二つは少し正しいとはいいがたいです。
勘違いかも知れませんが、参考にしたサイトでは唐突にこの謎変換が起きていて理解が進まなくなっていました。
>>8-1が自分の勘違いかによっても位置づけが変わってくるので、後でもう少し考えてみたいですが、今からあのサイトを読み直すのはキツい…
>>9
おっしゃる通りです。元々は米田の補題とOperationalモナドの2つの記事となる構想でした。
力尽きてしまったため未完成の記事を増やす愚を軽減すべく両者を同居させています。
俺、この記事が完成したら、故郷に帰って分割するんだ… -
👍0高評価👎0低評価
-
12
ななしのよっしん
2021/05/23(日) 13:41:19 ID: vV4BLHkd1O
-
>>11
失礼しました、Coyoneda fのfmapの実装ですね。それでしたら、下のように実装できます。
data Coyoneda f a = forall x. Coyoneda (x -> a) (f x)
instance Functor (Coyoneda f) where
fmap f (Coyoneda g h) = Coyoneda (f . g) h
それぞれの型を捕捉すると、
fmap :: (a -> b) -> Coyoneda f a -> Coyoneda f b
f :: a -> b
g :: x -> a
h :: f x
f . g :: x -> b
* (.)は次を満たす関数合成演算子, g(f(a)) == (g . f)(a)
圏論は筆者によって結構図や式の書き方に違いがあるので、その文脈では正しいのかもしれないですね。しかし、ここまでで用いてきたような記法とは齟齬がありそうです。
Haskellの文法が分かるのであれば、この辺なんかが参考になるかもしれません。
https://ryota-ka .hatenab log.com/ entry/20 18/07/03 /021216
-
👍0高評価👎0低評価
-
13
ななしのよっしん
2021/05/24(月) 22:25:24 ID: fumz9DZAK9
-
👍0高評価👎0低評価
-
14
ななしのよっしん
2021/05/25(火) 15:18:36 ID: vV4BLHkd1O
-
👍0高評価👎0低評価
-
15
ななしのよっしん
2021/06/04(金) 21:18:54 ID: fumz9DZAK9
-
>>12
参りました。2週間近く考えても、何を聞けばいいのかすらわからない。
とりあえず以下について確認させて下さい。
1.
> data Coyoneda f a = forall x. Coyoneda (x -> a) (f x)
これはFreeモナドみたいな再帰的定義ということでよろしいでしょうか。
2. 関手(Functor)について
2-1:
一般に圏から圏への射と表現されますが、圏が対象と対象間の射からなる以上、
関手は「対象と射」を別の「対象と射」に変換するものということであっていますでしょうか。
2-2:
2-1のプログラミング上の実装は、
元のクラス(型)の「値」を別のクラスの「値」に変換する関数と、
「元のクラスの値を引数に取る関数」を「別のクラスの値を引数に取る関数」に変換する関数、
が合わさったものになると思っているのですが、間違っているところがありますでしょうか。
2-3:
>>12において、fmapが2-1の「変換するもの」という解釈でよろしいでしょうか。
それともクラス(型)をクラス(型)に変換するCoyoneda fが「圏から圏への変換」にあたるのでしょうか。 -
👍0高評価👎0低評価
-
16
ななしのよっしん
2021/06/11(金) 22:03:47 ID: vV4BLHkd1O
-
>>15
1. 違います。>>14 で提案した通り、Haskellの文法で代数的データ型の定義する方法を調べてください。
2-1. その通りです。
例えば、関手はF: C -> Dは、任意の対象X∈Obj(C)をF(X)∈Obj(D)に移し、任意の射f∈Mor(C)をF(f)∈Mor(D)に移します。
2-2. 少し違います。
Haskellでは型を対象、関数を射としている(Hask圏)ので、「ある型を受け取って別の型を返すもの」が関手になりうることになります。
「元のクラスの値を引数に取る関数」を「別のクラスの値を引数に取る関数」で言わんとしていることは合っているように思います。
2-3. 少し違いますかね。
2-1で示した通り、関手は対象の変換と射の変換の組です。
fmapはそのうち射の変換を行っているものです。
型を型に変換するCoyoneda fは対象の変換を行っているものです。
Coyoneda fとfmapを合わせて初めて圏から圏への変換ができる、つまり関手として成り立つということになります。
-
👍0高評価👎0低評価
-
17
ななしのよっしん
2021/06/12(土) 09:05:23 ID: fumz9DZAK9
-
>>16
ありがとうございます。ヤクの毛刈り状態ですが、この記事や親記事でも少し触れている長年の疑問がちょっとずつですが解決しているので助かります。
1 調べて、forallは型スキーマ(型抽象)を表わし、型の世界のλである。
https://uehaj.ha tenablog .com/ent ry/2014/ 01/23/12 1923 
ということは理解していましたが、
これだけと左辺と右辺にCoyonedaが来ることを解釈できませんでした。
他の代数的データ型の解説はたいてい列挙型・直積型・直和型くらいで終わっており、
https://qiita.co m/7shi/i tems/1ce 76bde464 b4a55c14 3 
やはり左辺と右辺に同じものが来るのは、再帰的定義と解釈せざるを得なかったです。
2-2
> Haskellでは型を対象
値が対象でないというのは目から鱗かも。
あれ? ということは、Functorは元のクラス(型)の「値(オブジェクト指向でいうところのインスタンス)」を
別のクラスの「値」に変換する関数を提供しないということでしょうか。 -
👍0高評価👎0低評価
-
18
ななしのよっしん
2021/06/12(土) 19:17:31 ID: vV4BLHkd1O
-
>>17
1.
CoyonedaはHaskell上では直積型で表されていますので、参考にされた記事の上記記事の直積型の構文と例を見てください。
https://qiita.co m/7shi/i tems/1ce 76bde464 b4a55c14 3#%E7%9B %B4%E7%A 9%8D%E5% 9E%8B 
> data 型 = コンストラクタ [フィールドの型 ...]
>
> data Point = Point Int Int deriving Show
ここで、右辺に現れるPointはコンストラクタです。同様に、
data Coyoneda f a = forall x. Coyoneda (x -> a) (f x)
という定義の右辺に出てくるCoyonedaはフィールドの型ではなくコンストラクタであり、再帰的定義ではありません。
2-2.
はい、その通りです。
>元のクラス(型)の「値(オブジェクト指向でいうところのインスタンス)」を別のクラスの「値」に変換する関数
というのは、型で表すと a -> f a というような関数になりますが、これはHaskellでいうApplicativeのpure(= Monadのreturn)が担っている機能です。
-
👍0高評価👎0低評価
-
19
ななしのよっしん
2021/06/12(土) 19:42:48 ID: vV4BLHkd1O
-
余談ですが、代数的データ型を定義するときの左辺を「型コンストラクタ」右辺を「値コンストラクタ」と言ったりします。
下のような直積型は、
data A a = A a a
例えばJavaで書くと次のような定義になりますが、
> class A<T> {
> public A(T a, T b) {
> this.a = a;
> this.b = b;
> }
> public T a;
> public T b;
> }
型宣言のA a(A<T>)は「型を1つ受け取って型を作るもの」、コンストラクタAは「値を2つ受け取って値を作るもの」とみなせます。
ここで、型コンストラクタはAは型aを型A aに変換するものと言えるので、これが関手の対象の変換に相当するものとなるわけです。
理解の助けになればと思います。 -
👍0高評価👎0低評価
-
20
ななしのよっしん
2021/06/12(土) 22:03:07 ID: fumz9DZAK9
-
👍0高評価👎0低評価
-
21
ななしのよっしん
2021/06/25(金) 23:21:55 ID: fumz9DZAK9
-
何度もお手数をおかけして申し訳ございません。
>>12
data Coyoneda f a = forall x. Coyoneda (x -> a) (f x)について
左辺は左結合((Coyoneda f) a)で型クラスfがCoyonedaの型引数になっているのに対し、
右辺の(f x)はfがxを型引数にしているという解釈であっていますでしょうか。
昔Haskellの文法を勉強したことはあるのですが、このように結合方向とかで、fが引数になったり、引数をとる側に回ったりというのが、文法に精通していないと読むことすらできないので、いまだに馴染めずにいます。
ただfを型クラスと考えると、fmapが型クラスを引数に取る関数ということになって、関数と呼んでいいものかわからなくなってしまうのですが、
instance Functor (Coyoneda f) where
fmap f (Coyoneda g h) = Coyoneda (f . g) h
の1行目のfと2行目の左辺と2行目の右辺のf、及び代数データ型の定義の左辺で出てきたfは同じものを指している(同じ型クラスをあてはめられる?)ということであっていますでしょうか。 -
👍0高評価👎0低評価
-
22
ななしのよっしん
2021/06/27(日) 17:34:38 ID: vV4BLHkd1O
-
>>21
左辺 data Coyoneda f a は、
型fと型aを引数に取るCoyonedaという型を宣言するという意味です。
右辺 forall x. Coyoneda (x -> a) (f x) は、左辺で宣言したCoyoneda f aの定義がこの通りであるという意味で、f xの解釈は仰る通りです。
そうですね、Haskellは独特の文法を持っていて、慣れるまで読みづらい言語ではあると思います。ただ、米田の補題をHaskellの文脈で理解したいというのであれば、Haskellの文法を勉強は避けられないと思います。このレスを含め、私の解説はほぼHaskellの文法解説になってきているわけですし。
せっかく実際に動くコードなのですから、動かして遊んでみたら理解も深まるのではないでしょうか。
https://ideone.c om/l1sh9 Q 
fは型クラスではく、高階型と呼ばれるものです。
Haskellの型には、カインド(kind, 種)という、型の型とも呼べるものがあります。
明示的に書くとf :: * -> *、 a :: * となり、fは「カインド*の型を受け取ってカインド*の型になるような型」というわけです。
> instance Functor (Coyoneda f) where
> fmap f (Coyoneda g h) = Coyoneda (f . g) h
> の1行目のfと2行目の左辺と2行目の右辺のf、及び代数データ型の定義の左辺で出てきたfは同じものを指している(同じ型クラスをあてはめられる?)ということであっていますでしょうか。
いいえ、合っていません。
一行目のfは、代数的データ型の定義の左辺のfにこのfを割り当てているということです。
Functorはカインド* -> *を持つ型しかインスタンスに取れません。CoyonedaはCoyoneda :: (* -> *) -> * -> *というカインドを持つため、fを当てはめてやるとCoyoneda f :: * -> *となってFunctorのインスタンスに取れるようになるということです。
二行目のfは、単にfmapの第一引数の仮引数名です。 -
👍0高評価👎0低評価
-
23
ななしのよっしん
2021/06/29(火) 00:11:39 ID: fumz9DZAK9
-
👍0高評価👎0低評価
-
24
ななしのよっしん
2021/12/08(水) 17:33:03 ID: YUQV4ejAYU
-
個人的に米田の補題を調べていてここにたどり着いたのですが、具体的な使い方がある程度わかったほうが全体像が把握しやすいということもあると思うので、自分としてはいきなりOperationalモナドから入るのもありなのではないかと思います。
そうは言っても結局米田の補題の理解が問題になるわけですが…
仕組みとしては、自分はhttps://its-out- of-tune. hatenadi ary.org/ entry/20 130601/1 37010974 3
の解説が一番わかりやすかったのですが、おそらく理論として重要なのはHom(A,-)からの変換とF(A)の組が一対一に対応する(どちらかが重複したりしない)という点なのかなと思います。
正直自分もよく分かってない -
👍0高評価👎0低評価
-
25
ななしのよっしん
2022/06/30(木) 06:04:50 ID: YUQV4ejAYU
-
👍1高評価👎0低評価
-
26
ななしのよっしん
2022/07/08(金) 15:33:37 ID: Ji1cau+BJr
-
構造や中身に関していくつか書かせていただきます。
1.「概要」は全体的に意味が不明瞭です。ただ説明方法の代案は思いついておらず申し訳ないです。
2.「Operationalモナド」について。ここで主に書かれているのはCoyonedaについてであるため名前を変更した方が良さそうです。
また、米田の補題とHaskellでCoyonedaと呼ばれているものは、co-Yoneda lemmaで繋がっているわけですが、そのあたりがわかりにくいのでhttps://ncatlab. org/nlab /show/co -Yoneda+ lemma
あたりの中身を可能なら盛り込みたい気持ちになりました。(多分相当難しいですが)
3. 「ファンクター・アプリカティブ」は米田の補題との関連性がはっきりしない気がします。「関手」の記事とマージしてよさそうです。
自分でこのページを書き直すとしたら、HaskellのCoyonedaには触れたいですが、Operationalモナドは自由モナド寄りという気がするので、「Freeモナド」に移動して、ここでは軽く触れるくらいにしたいですね。 -
👍0高評価👎0低評価
-
27
ななしのよっしん
2022/07/09(土) 06:36:14 ID: fumz9DZAK9
-
👍0高評価👎0低評価
-
28
ななしのよっしん
2022/07/09(土) 19:48:12 ID: Ji1cau+BJr
-
👍0高評価👎0低評価
-
29
ななしのよっしん
2022/07/09(土) 20:01:54 ID: fumz9DZAK9
-
👍0高評価👎0低評価
-
30
ななしのよっしん
2022/07/11(月) 07:51:38 ID: YUQV4ejAYU
-
👍0高評価👎0低評価

