あ、俺はまったくここら辺 (圏論、モナド) の話は自信が無いので、みなさん全力で疑って読んでください。
とりあえずコンテキストを関数として扱うという話なので、コンテキスト (これは今までは辞書だったもの) を関数に直す所から始めてみよう。
def make_context(ctx): # ctx は {key: value}という辞書とする。
def context(key):
return ctx.get(key, key) # 対応するデータが無ければ、キーを返す。そうしてる理由は面倒だから
return context
早速自分で書いてて「うそぉこれでいいの?」って感じなのだけど、まあいいやとりあえず進もう。次は processTemplate。
def processTemplate(t, con):
def _process():
start_bracket = False
placeholder = []
for c in t:
if c == '{':
start_bracket = True
elif c == '}' and start_bracket:
key = ''.join(placeholder)
yield con(key) # 前は dict.get でやってた
start_bracket = False
placeholder = []
else:
if start_bracket:
placeholder.append(c)
else:
yield c
return ''.join(_process()) # 普通の文字列として返す
ま、これはそのまんまだな。前に書いた奴をちょっと変えて、文字列にして返すのが違うけど。次は俺にとっては早速大問題の「con:A→Templ(B) を、 Templ(A)→Templ(B) へと拡張する」関数 ext。
def ext(f): # f は context だと決め打ち
def con_ext(t):
return processTemplate(t, f)
return con_ext
確かに ext(make_context(ctx))(tmpl) は processTemplate(tmpl, make_context(ctx)) になるけどさー。まあ動かしてみたらあってるっぽかったからいいや、課題 7 終わり。間違ってたら絶対に課題 8 のどこかで引っかかるだろ。
そして課題 8 だが、これはつまり unit さえばいいんだな。つーわけで、 unit を作る関数を作ればいいわけだ。
def make_unit(ctx):
def unit(key):
if key in ctx:
return '{%s}' % key
else:
return None
return unit
なんだか申し訳ない気分になってきた。これマジであってるのか? とりあえず次のような感じで実行してみた。
tmpl = u"こんにちは、{お客様名}様。{来店日}にはご来店いただき、まことにありがとうございます。"
ctx = {
u"お客様名" : u"板東トン吉",
u"来店日" : u"1月21日"
}
print processTemplate(tmpl, make_context(ctx))
print ext(make_context(ctx))(tmpl)
# (ext(unit))(t) = t
print ext(make_unit(ctx))(tmpl)
# (ext(con))(unit(x)) = con(x)
x = u"来店日"
con = make_context(ctx)
unit = make_unit(ctx)
print ext(con)(unit(x))
print con(x)
# ext((ext(con2))・con1) = ext(con2)・ext(con1)
# Python には関数合成が無いので lambda 式で
c1 = {u"お客様名" : u"板東トン吉"}
c2 = {u"来店日" : u"1月21日"}
con1 = make_context(c1)
con2 = make_context(c2)
n = lambda a: ext(con2)(ext(con1)(a))
m = ext(lambda a: ext(con2)(con1(a)))
print n(tmpl)
print m(tmpl)
実行結果。
こんにちは、板東トン吉様。1月21日にはご来店いただき、まことにありがとうございます。
こんにちは、板東トン吉様。1月21日にはご来店いただき、まことにありがとうございます。
こんにちは、{お客様名}様。{来店日}にはご来店いただき、まことにありがとうございます。
1月21日
1月21日
こんにちは、板東トン吉様。来店日にはご来店いただき、まことにありがとうございます。
こんにちは、板東トン吉様。来店日にはご来店いただき、まことにありがとうございます。
うそぉ、何で動いてるの!? <- 未だに全然自信が無いらしい
あってる自信が全然ないものの、とりあえず解き終わった。なんだか圏論やモナドが少しはわかった気がするようなしないような。まだ全然応用できそうに無いけど、 Python でもそれっぽいものは比較的簡単にエミュレートできるのがわかっただけでもめっけもんだ。でもこれ、強い静的型の言語でやった方が有難味がある気がしなくもないなあ。
さらにいい加減なことを書かせてもらうと、これは Relax NG とかのスキーマとプログラム生成に関わってる気がしなくもない。なんとなく、テンプレートの展開とスキーマによる検証とそこからのプログラム生成に近いものを感じたってだけなんだけど。まあ、そういうことはまたいつか考えよう。