Rustで圏論(3) 圏はトレイトでは?
前回の話
前回、同型かどうかを判断するコードの中に間違いがあるという話を書きました。 中心となる処理は以下です。
fn is_isomorphism(&self, object1: &str, object2: &str) -> bool { self.has_arrow(object1, object2) && self.has_arrow(object2, object1) }
与えられた2つの対象でf: A->Bとg: B->Aの射が存在していれば、同型である。 と書いてあるように見えるんですけど、これだと全然定義通りじゃなかったですね。すいません。 f;g = 1A かつ g;f = 1Bじゃないとダメです。そもそも、射の合成も恒等射もないですし。
そもそも、圏はstructじゃなくてtraitなのでは
話題が変わってしまいますが、当初はstructでCategoryを定義したものの、これだとあんまりしっくりきません。 「圏というもの」が存在する、というよりはいろんなものが「圏と見なせる」というケースが多い気がするためです。 というわけで、structではなくtraitで実装し直してみました。今度は圏の定義に忠実に。
use std::cmp::PartialEq; 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() -> HashSet<Self::Object>; fn arrows() -> HashSet<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 } }
下の3つは公理なんですが、証明系の言語ではないので、定義したものの使いどころがわからない。 traitをimplementする側が保証しないといけないわけです。Haskellの型クラスもそうですね。 具体例も徐々に書いていきましょう。