PythonでLispのcondっぽくパターンマッチング(条件分岐) その2
昨日のつづき。ちょっとだけ進化させて、デコレータを使ってC言語のswitch 〜 case文みたく書けるようにしてみます
(まだまだ名前空間が汚染してますが、一足飛びにやらずに、まず1ステップだけ進めてみます)
条件式の境界テストと、関数の中身の単体テストが、それぞれ個別に行えてます。。。といいつつも、再帰だと、関数の単体テストが面倒なのですが。
単一のpythonファイルですがブロックごとにわけて表記
Condクラス
# -*- coding: utf8 -*- from __future__ import print_function class Cond(object): def __init__(self): self.condlist=[] def __call__(self,*args,**kwargs): for c,f in self.condlist: if c(*args,**kwargs): return f(*args,**kwargs) else: pass #for decorator def case(self,cond): def _(f): self.condlist.append((cond,f)) f.__case__=cond return f return _
フィボナッチ数列関数 (分岐)
_fib=Cond() @_fib.case(lambda n,x1,x2:n==0) def _fib_0(n,x1,x2): return 0 @_fib.case(lambda n,x1,x2:n==1) def _fib_1(n,x1,x2): return x2 @_fib.case(lambda n,x1,x2:True) def _fib_n(n,x1,x2): return _fib(n-1,x2,x1+x2) #エントリーポイント def fib(n): return _fib(n,0,1)
テスト
#条件のテスト assert _fib_0.__case__(0,0,1) and not _fib_0.__case__(1,1,2) assert _fib_1.__case__(1,1,2) and not _fib_1.__case__(3,0,1) import random assert _fib_n.__case__(random.randint,0,1) #関数の中身のテスト assert _fib_0(0,0,1)==0 assert _fib_1(1,0,1)==1 assert _fib_n(3,0,1)==2 #再帰の場合は、関数の中身の単体テストめんどくさい #結合テスト testcase=[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89,144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946] for i in xrange(len(testcase)): ret=fib(i) assert ret==testcase[i] print(i,ret)