読者です 読者をやめる 読者になる 読者になる

PythonでHaskellのMaybeモナド(もどき)を実装してみる

Haskellを勉強してきて、ようやくモナドの雰囲気がわかってきたので、Maybeモナドのような計算をPythonでやってみる。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# instance Monad Maybe where
#     return         = Just
#     fail           = Nothing
def Maybe(x):
    return Just(x) if x else Nothing()

class Just:
    def __init__(self, x):
        self.value = x

    def __repr__(self):
        return "Just(%r)" % self.value

    # (Just x) >>= f = f x
    def bind(self, f):
        return f(self.value)

    # '>>=' の代わりに '>>' をbind演算子として定義してみる
    def __rshift__(self, other):
        return self.bind(other)

class Nothing:
    def __repr__(self):
        return "Nothing()"

    # Nothing >>= f = Nothing
    def bind(self, f):
        return self

    def __rshift__(self, other):
        return self.bind(other)


nested_dict = {'a': {'b': {'c': 42}}}

# あるキーで辞書を引く関数を返す関数
def lookup(key):
    return lambda d: Maybe(d.get(key))

print Maybe(nested_dict).bind(lookup('a')).bind(lookup('b')).bind(lookup('c'))
# => Just(42)
print Maybe(nested_dict) >> lookup('a') >> lookup('b') >> lookup('c')
# => Just(42)

print Maybe(nested_dict).bind(lookup('a')).bind(lookup('X')).bind(lookup('c'))
# => Nothing()
print Maybe(nested_dict) >> lookup('a') >> lookup('X') >> lookup('c')
# => Nothing()

returnがプリミティブ値をモナドに入れて、bindがモナドの中身に何らかの処理をして新たなモナドを作る、do記法はbindの繰り返しを見やすく書くための糖衣構文、というあたりまでは掴めてきた。