« モナドはごちそうさま日記 |Main| 執筆プロトタイピング日記 »

« モナドはごちそうさま日記 | zakki(雑記) | 執筆プロトタイピング日記 »

モナドを作るver. 0.1

IOモナドは難しそうだったのでとりあえずMaybeモナドからはじめる。
>>> def Maybe(typ):
	class Foo(object):
		@classmethod
		def return_(_, x):
			return Just(x)
		@classmethod
		def bind(_, m, f):
			if isinstance(m, Nothing):
				return Nothing()
			elif isinstance(m, Just):
				return f(m.value)
	class Just(object):
		def __init__(self, x):
			assert isinstance(x, typ)
			self.value = x
	class Nothing(object):
		pass
	Foo.__name__ = "Maybe_%s" % typ.__name__
	return Foo
これで型を受け取って型を返す関数ができました。 Maybe Intみたいに呼び出してみよう。
>>> Maybe(int)
<class __main__.Maybe_int at 0x00D750F0>
「Maybe Int」型ができました。
>>> MaybeInt = _
>>> MaybeInt.return_(1)
<__main__.Just object at 0x00D57F70>
「return 1」で「Just 1」ができます。 「MaybeInt.」と書かないといけないのは、Pythonに 引数の型の情報を使って適切な関数を選択する機能がないから。

適当な関数を作ってbindしてみましょう。

>>> def inc(x): #:: int -> Maybe int
	return MaybeInt.return_(x + 1)

>>> MaybeInt.bind(_, inc)
<__main__.Just object at 0x00D57A90>
>>> _.value
2
できました。

でも、これじゃIOモナドには進めません。 なぜかというと、x + 1の計算がbind時に行われているから。 ここの評価を遅延させる必要があります。

>>> class Lazy:
	def __init__(self, expr):
		self.expr = expr
		self.value = None
	def force(self):
		if self.value == None:
			print self.expr, "を評価します"
			self.value = self.expr.force()
		return self.value
	
>>> class Literal:
	def __init__(self, value):
		self.value = value
	def force(self):
		return self.value

>>> class LazyAdd(object):
	def __init__(self, a, b):
		self.a = a
		self.b = b
		self.value = None
	def force(self):
		if self.value == None:
			self.value = self.a.force() + self.b.force()
		return self.value

>>> def inc(x): #:: int -> Maybe int
	return MaybeInt.return_(LazyAdd(x, Literal(1)))
これで試そうと思ったのですけど、 intをLazyで包んでしまうと、 MaybeIntの型チェックで「intじゃなくてLazyだ」と怒られてしまうので 型チェックを削除。

ああ、でも本当は 「評価前」「評価後」という2状態じゃないんだなぁ。 パターンマッチの書かれ方によって、 どこまで評価するかが決まるのか…。

IOで「入力用モナドと出力用モナドをつなぐだけでwhileも書いていないのに ループしてくれる」 というような説明があるけども、 それは入出力用のモナドの中の実装が見えていないから魔法みたいに見えるだけ。

>>> def printStr(x):
	while True:
		v = x.force()
		if v == "[END]":
			break
		print v

		
>>> def inputStr():
	class LazyInput:
		def force(_):
			return raw_input()
	return LazyInput()

>>> printStr(inputStr())
111
111
222
222
[END]
このコードの「printStr(inputStr())」だけ見せられれば、 そりゃ魔法みたいにも見える。

トラックバック(Trackback)

Trackback URL: http://www.nishiohirokazu.org/mt/mt-tb.cgi/538

ご意見・ご感想をお送りください(フィードバック)

(フィードバックはメールで送信され、基本的に表示されませんが、内容によっては公開させていただくこともございます。ご了承ください。Your comment doesn't appear the page immediately. If the comment has value to other people, it will be put on the page or subsequent entries. Thank you.)

上の情報は、いずれも未記入でかまいません。 All of above questions are optional.