Rustで圏論(4) ゼロ圏を作る
対象の族と射の族の型を変更した
今回定義している圏のトレイトCategory
の中には、対象のHashSet
(C0)と射のHashSet
(C1)を返すメソッドが定義されていました。今回、思うところもあってHashSet
からIterator
に変更しました。気分の問題といえばそこまでですが、C0もC1も集合になるとは限らないので。Iterator
であれば、色々便利そうだな、という目論見も含めての変更です。
トレイト内でimpl trait
は使えない
impl trait
が安定化してから初めてコードを書いているので、嬉しくてさっそく、圏のトレイトの定義に使ってみようとしたのですが、inherentな関数じゃないと使えません、とコンパイラに怒られてしまいました。しかたなく、今まで通りBox<Iterator<Item>>
にすることで落ち着きました。
trait Category { type Object: PartialEq; type Arrow: PartialEq; fn domain(&self, f: &Self::Arrow) -> Self::Object; fn codomain(&self, f: &Self::Arrow) -> Self::Object; fn identity(&self, a: Self::Object) -> Self::Arrow; fn composition(&self, f: Self::Arrow, g: Self::Arrow) -> Option<Self::Arrow> { if self.codomain(&f) != self.domain(&g) { None } else { Some(self.composition_internal(&f, &g)) } } fn composition_internal(&self, f: &Self::Arrow, g: &Self::Arrow) -> Self::Arrow; fn ci(&self, f: &Self::Arrow, g: &Self::Arrow) -> Self::Arrow { self.composition_internal(f, g) } fn objects() -> Box<Iterator<Item=Self::Object>>; fn arrows() -> Box<Iterator<Item=Self::Arrow>>; fn associativity(&self, f: Self::Arrow, g: Self::Arrow, k: Self::Arrow) -> bool { self.ci(&self.ci(&f, &g), &k) == self.ci(&f, &self.ci(&g, &k)) } fn unit_law_domain(&self, o: Self::Object, f: Self::Arrow) -> bool { self.ci(&self.identity(o), &f) == f } fn unit_law_codmain(&self, o: Self::Object, f: Self::Arrow) -> bool { self.ci(&f, &self.identity(o)) == f } }
まずはゼロ圏を作ってみる
「ゼロ圏」という呼び方が正しいのか自信がないです(書籍にはローマ数字の0がそのまま記号として使われている印象)。ともかく、impl
するのが簡単そうなので、ここから始めてみることにします。
impl Category for Zero { type Object = (); type Arrow = (); fn domain(&self, _f: &()) {} fn codomain(&self, _f: &()) {} fn identity(&self, _a: ()) {} fn composition_internal(&self, _f: &(), _g: &()) {} fn objects() -> Box<Iterator<Item=()>> { Box::new(empty()) } fn arrows() -> Box<Iterator<Item=()>> { Box::new(empty()) } }
std::iter::empty
を初めて使ってみました。空のイテレータって中身がないのでこう書けるのは煩雑にならなくて便利ですね。Object
もArrow
も()
にしたのは、実装の見た目がスッキリするから以上の理由はありません。Unit自体はぜろというより1(対象が1つと恒等射のみからなる圏)ですけどね、イメージとしては。まあいっか。