原始帰納的関数のPythonでの表現
原始帰納的関数の定義がよくわからなかったので数学事典で調べてみた。数学語で書いてあるけど、Python語に翻訳してみると:
def inc(x): return x + 1 def constant(*args): return CONSTANT def choice_K(*args): return args[K]
という関数からスタートして(constantとchoiceは返す定数や選ぶ引数の位置によって無数に存在する)
def apply_funcs(*args): return REDUCE_FUNC( MAP_FUNC_TABLE[0](*args), MAP_FUNC_TABLE[1](*args), ...) def recursive(*args): head = args[0] tail = args[1:] if head == 0: return WHEN_ZERO_FUNC(tail) else: return OTHERWISE(y, recursive(y - 1, *tail), *tail)
という関数を繰り返し適用して作ることのできるもの、となる。
さて、実際にコードを書いて試してみるために、上のざっくりとしたPython訳をしっかりした訳にしてみよう。主に「constantとchoiceは返す定数や選ぶ引数の位置によって無数に存在する」という日本語で書いてある部分がダメなので、これをコードで表現する。パラメータによって無数に定義の存在する関数ってのはPython語ではクラスっていう。
# -*- coding: utf-8 -*- def inc(x): return x + 1 class Constant: def __init__(self, CONSTANT): self.CONSTANT = CONSTANT def __call__(self, *args): return self.CONSTANT class Choice: def __init__(self, WHERE): self.WHERE = WHERE def __call__(self, *args): return args[self.WHERE] class ApplyFuncs: def __init__(self, REDUCE_FUNC, MAP_FUNCS): self.REDUCE_FUNC = REDUCE_FUNC self.MAP_FUNCS = MAP_FUNCS def __call__(self, *args): return self.REDUCE_FUNC( *[self.MAP_FUNCS[i](*args) for i in range(len(self.MAP_FUNCS))]) class Recursive: def __init__(self, WHEN_ZERO_FUNC, OTHERWISE): self.WHEN_ZERO_FUNC = WHEN_ZERO_FUNC self.OTHERWISE = OTHERWISE def __call__(self, *args): head = args[0] tail = args[1:] if head == 0: return self.WHEN_ZERO_FUNC(*tail) else: return self.OTHERWISE(head, self(head - 1, *tail), *tail) # x + yを定義する add = Recursive( # xが0ならyそのもの WHEN_ZERO_FUNC=Choice(0), # xが0でないならadd(x, y)はinc(add(x - 1, y)) OTHERWISE=ApplyFuncs( REDUCE_FUNC=inc, MAP_FUNCS=[Choice(1)] )) print add(2, 3) #-> 5 """ MEMO add(2, 2) -> OTH(2, add(1, 2), 2) -> OTH(2, OTH(1, add(0, 2), 2), 2) -> OTH(2, OTH(1, 2, 2), 2) -> OTH(2, inc(Choice1(1, 2, 2)), 2) -> OTH(2, inc(2), 2) -> OTH(2, 3, 2) -> inc(Choice1(2, 3, 2)) -> inc(3) -> 4 """
とりあえず、足し算が原始帰納的関数であることまではコードで表現できた。このパズルはけっこう面白い。足し算は何とかなったけど、他にもx * y, x ^ y, x!, min(x, y), max(x, y), abs(x - y), x == y, x < y, xはyで割り切れる, xは素数である, x番目の素数, なども全部原始帰納的だそうな。
掛け算も作った。
# x * yを定義する mul = Recursive( # xが0なら0 WHEN_ZERO_FUNC=Constant(0), # xが0でないならmul(x, y)はadd(x - 1, y) + yで、 # OTH(x, add(x - 1, y), y)の最初の引数を無視して残りにaddを使うために # RecursiveのWHEN_ZEROを使う OTHERWISE=Recursive( WHEN_ZERO_FUNC=add, OTHERWISE=Choice(1))) print mul(5, 7) #-> 35