[SML 7870] 連想計算というリフレクティブな手法
AOKI Atsushi
atsushi @ cc.kyoto-su.ac.jp
2010年 12月 13日 (月) 17:40:38 JST
青木@京都上賀茂です。
フィボナッチ数を求めるプログラムは、通常、以下のようになりま
すが、40ぐらいのフィボナッチ数を求めるあたりから、ものすごい
手間がかかりだします。2のn乗のオーダーで計算量が増加です。
------------------------------------------------------------
Core.Integer methods for 'mathematical functions'
fibonacci
"12 fibonacci."
"40 fibonacci."
self negative ifTrue: [^nil].
self = 0 ifTrue: [^0].
self = 1 ifTrue: [^1].
^(self - 1) fibonacci + (self - 2) fibonacci
------------------------------------------------------------
それを軽減するためには、連想計算というリフレクティブな手法を
用いるのが効果的であることが知られています。本日、学生とペア
プログラミングしながら作りましたので、それを紹介しておきます。
------------------------------------------------------------
Core.Integer methods for 'mathematical functions'
fibonacci
"12 fibonacci."
"100 fibonacci."
| aValue aCode aString anIndex |
self negative ifTrue: [^nil].
self = 0 ifTrue: [^0].
self = 1 ifTrue: [^1].
aValue := (self - 1) fibonacci + (self - 2) fibonacci.
[aCode := Integer sourceCodeAt: #fibonacci.
aString := 'aValue :='.
(anIndex := aCode findString: aString startingAt: 1) > 0
ifTrue:
[| aStream |
aStream := (String new: aCode size + 1024) writeStream.
[(1 to: anIndex - 1) do: [:index | aStream nextPut: (aCode at: index)].
aStream
nextPutAll: 'self = ';
nextPutAll: self printString;
nextPutAll: ' ifTrue: [^';
nextPutAll: aValue printString;
nextPutAll: '].';
crtab.
(anIndex to: aCode size) do: [:index | aStream nextPut: (aCode at: index)].
aCode := aStream contents] ensure: [aStream close].
Integer compile: aCode classified: #'mathematical functions']]
on: Object errorSignal
do: [:anException | anException return].
^aValue
------------------------------------------------------------
プログラムの実行中に、その実行中のプログラム自身を書き換えて
(コンパイルし直して)います。まさに動的な(フルな)リフレク
ションになりますでしょ。100ぐらいのフィボナッチ数も平気です。
もっといいやり方がありますので、皆さんで模索してくださいませ。
参考のため、じゅんのLisp版とProlog版も添えておきます。
------------------------------------------------------------
(defun fibonacci (n)
(cond ((not (integerp n)) nil)
((< n 0) nil)
((= n 0) 0)
((= n 1) 1)
(t (+ (fibonacci (- n 1))
(fibonacci (- n 2))))))
------------------------------------------------------------
(defun fibonacci (n)
(cond ((not (integerp n)) nil)
((< n 0) nil)
((= n 0) 0)
((= n 1) 1)
(t (do (value assertion condition target clauses)
(setq value (+ (fibonacci (- n 1))
(fibonacci (- n 2)))
assertion (list (list '= 'n n) value)
condition (nth 4 (getprop 'fibonacci 'expr))
target (last condition)
clauses (list (car target)))
(rplaca target assertion)
(rplacd target clauses)
value))))
------------------------------------------------------------
fibonacci(0,0).
fibonacci(1,1).
fibonacci(N,F) :-
integer(N),
>(N,1),
-(N,1,N1),
-(N,2,N2),
fibonacci(N1,A1),
fibonacci(N2,A2),
+(A1,A2,F).
------------------------------------------------------------
fibonacci(0,0).
fibonacci(1,1).
fibonacci(N,F) :-
integer(N),
>(N,1),
-(N,1,N1),
-(N,2,N2),
fibonacci(N1,A1),
fibonacci(N2,A2),
+(A1,A2,F),
asserta([fibonacci(N,F) :- !]).
------------------------------------------------------------
AOKI Atsushi http://www.cc.kyoto-su.ac.jp/~atsushi/
SML メーリングリストの案内