[D 語言] SumOfSquare

這是『爪哇學校的危害』一文裡提到的問題,原本是用 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)
    );

}

回響