「ひらがなのしりとり圏」 in Python
完全実装付きでもう一度お送りします、しりとりの圏 - 檜山正幸のキマイラ飼育記のJavaScriptによるしりとりの圏の実装をPythonに移植しながら読んだ。圏論がわかった気がする!
僕の理解が正しければ
「対象aに対する恒等射」は一つとは限らない- 対象「あ」に対する恒等射が「あああ」でもよい
- わかった、id(x)がcomposeに対して単位元になるという条件から「あ」じゃないといけないんだな。firstとlastに関してだけ考えていた。
僕は文字と文字列の区別がないPythonでやってしまったので誤解を招くかもしれない。ObjectクラスとMorphismクラスを作って別物であることを明確にした方がいいかもしれない
理解できた気がするので、これを見ないでもう一度0から実装する。
# -*- encoding: utf-8 -*- """ 「ひらがなのしりとり圏」 in Python http://d.hatena.ne.jp/m-hiyama/20090424/1240552575 のPythonへの移植 """ def _force_unicode(s): if isinstance(s, str): s = unicode(s, "utf-8") return s def _print(s): if isinstance(s, unicode): s = s.encode("utf-8") print s def _is_hiragana(x): """ひらがな1文字かどうかを返すユーティリティ関数 >>> _is_hiragana('あ') True >>> _is_hiragana('あうー') False >>> _is_hiragana('x') False """ if not isinstance(x, basestring): return False x = _force_unicode(x) if len(x) != 1: return False if u'ぁ' <= x <= u'わ': return True if x in u"をんー": return True return False class Category(object): u"圏というものが共通に持つべき性質: 今回は空" class SiritoriCategory(Category): u"ひらがなしりとり圏の実装" @staticmethod def is_object(x): """引数xがこの圏の「対象(object)」であるかどうか。 ひらがなしりとり圏のobjectは1文字のひらがな。""" return _is_hiragana(x) @staticmethod def is_morphism(x): """引数xがこの圏の「射(morphism)」であるかどうか。 ひらがなしりとり圏のobjectはひらがなで構成された空でない文字列。 >>> SiritoriCategory.is_morphism("たぬき") True >>> SiritoriCategory.is_morphism("たぬaき") False >>> SiritoriCategory.is_morphism("") False """ if not isinstance(x, basestring): return False if len(x) == 0: return False if all(_is_hiragana(char) for char in _force_unicode(x)): return True return False @staticmethod def get_domain(morph): """射(morphism)の域(domain)を求める >>> _print(SiritoriCategory.get_domain("たぬき")) た """ assert SiritoriCategory.is_morphism(morph) return _force_unicode(morph)[0] @staticmethod def get_codomain(morph): """射(morphism)の余域(codomain)を求める >>> _print(SiritoriCategory.get_codomain("たぬき")) き """ assert SiritoriCategory.is_morphism(morph) return _force_unicode(morph)[-1] @staticmethod def compose(m1, m2): """射(morphism)の合成(compose)を行う >>> _print(SiritoriCategory.compose("たぬき", "きつね")) たぬきつね """ assert SiritoriCategory.is_morphism(m1) assert SiritoriCategory.is_morphism(m2) m1 = _force_unicode(m1) m2 = _force_unicode(m2) assert m1[-1] == m2[0] return m1 + m2[1:] @staticmethod def id(x): """object xを受け取って恒等射を返す >>> _print(SiritoriCategory.id("あ")) あああ """ assert SiritoriCategory.is_object(x) return x def _test(): import doctest doctest.testmod() if __name__ == "__main__": _test()