2008-09-24 17:23 墳墓 (Brian Hsu)
這是『爪哇學校的危害』一文裡提到的問題,原本是用 Scheme / JavaScript 寫的,但很不巧的我兩個都不會,所以自己用 D 語言幹了一個同樣功能的版本。
另外,原始的問題中兩個版本的答案都沒有告訴你為什麼要這樣寫,和到底這個程式是怎麼跑的。雖然如果你熟悉遞迴的運作的話,應該花個十分鐘(是的,像我對遞迴已經很不拿少,但花點精神還是可以想出為什麼是這個答案的)就可以理解這個答案,但我還是把註解補上了。
當做展示 D 語言模版、匿名函式和 call by reference 強大之處的範例吧!
import tango.io.Stdout;
// combiner : combine function
// nullValue : 達到 recursion 邊界時的返迴值
// list : 要計算的 list
// (T) : 代表要處理的資料型態
T accumulate(T) (
T function (T x, T y) combiner,
T nullValue,
ref T [] list)
{
// 遞迴邊際條件是如果 list 已經空了
if (list.length == 0) {
return nullValue;
}
// 這兩行相當於 JavaScript 裡的
// list.shift()。
//
// 注意, list 一定要宣告成 ref 才可以,
// 不然會失效。
final auto first = list[0];
list = list[1 .. list.length];
// First 沒變過,代表 First 是下一個要
// 計算的,而後面的那一串則是已經計算完
// 的。
//
// 是的,實際上我們是從陣列的最後一個開
// 始平方。
return combiner ( first,
accumulate!(T) (
combiner,
nullValue, list));
}
T sumOfSquare (T) (T [] list)
{
// 既然如此,那麼我們的 combine
// function 自然就是把還沒計算的
// x 平方,再加上已經計算完的 y。
auto combiner = function T (T x, T y) {
T sum = x * x + y;
// 把計算過程印出來,就會一目了然
Stdout.format (
"x:{} * x:{} + y:{} = {}",
x, x, y, sum
).newline;
return sum;
};
return accumulate!(T) (combiner, 0, list);
}
void main ()
{
// 同樣的函式可以用在整數陣列上
auto integers = [1, 2, 3, 4, 5];
Stdout.format (
"sumOfSquare ({}) = {}\n\n",
integers,
sumOfSquare(integers)
);
// 浮點數陣列當然也可以
auto floats = [1.1, 2.2, 3.3, 4.4, 5.5];
Stdout.format (
"sumOfSquare ({}) = {}\n\n",
floats,
sumOfSquare(floats)
);
}
回響