おたっく's blog

プログラミングなど技術的なことを中心に書きます。

JavaScriptでSICPを勉強する その1

JavaScriptSICPを勉強する その1」です。「Schemeのコードを読んでも理解できないならJavaScriptで書いたら理解できるかも!」と思い記事を書きました。schemeJavaScriptのコードを見比べて理解を深めていきます。主に自分の理解を深めるために記事を書いているので説明が本に書いてある場合は適当に省きます。

1.1 プログラムの要素 (p.2)


schemeでの変数や関数の定義は次のようにします。

; 変数定義
(define pi 3.14159)
; 関数定義 (xの二乗を返す関数)
(define (square x) (* x x))

JavaScriptでは変数や関数の定義は次のようになるでしょう。

// 変数定義
var pi = 3.14159;
// 関数定義 (xの二乗を返す関数)
function square(x) { return x * x; };

schemeでは演算子が前置記法になっていてC言語, C++, Java, JavaScriptなどとは見た目が全然違うものに見えるかもしれませんが、順序が違うだけで本質的には変わらない部分が多いことを理解しましょう。

1.1.6 条件式と述語 (p.9)


次にschemeでの条件分岐とJavaScriptでの条件分岐を比べてみます。
scheme

; 一般形
(if <条件式> <trueのとき評価される式> <falseのとき評価される式>)

; 例 (絶対値を返す関数)
(define (abs x)
  (if (< x 0) 
    (- x)
    x))

JavaScript

// 一般形
if (<条件式>)
    <trueのとき評価される式>;
else
    <falseのとき評価される式>;

// 例 (絶対値を返す関数)
function abs (x) {
    if (x < 0)
        return -x;
    else
        return x;
}

1.1.7 例:Newton法による平方根 (p.12)


schemeJavaScriptでNewton法による平方根を求める処理を書いてみましょう。Newton法の説明は省きますが、Wikipedia:ニュートン法にも書いてあります。

scheme

; 関数sqrt-iterは推測値guessが目的値に充分近くなるまで計算を繰り返す
(define (sqrt-iter guess x)
  (if (good-enough? guess x)
    guess
    (sqrt-iter (improve guess x)
               x)))

; 関数improveは推測値guessをより良い値に改善して返す
(define (improve guess x)
  (average guess (/ x guess)))
; 関数averageは平均を返す
(define (average x y)
  (/ (+ x y) 2))

; 関数good-enough?は推測値guessが十分よい値になっているかどうかを返す(今回は差が0.001より小さいかどうか)
(define (good-enough? guess x)
  (< (abs (- (square guess) x)) 0.001))

; 関数sqrtは平方根を返す
(define (sqrt x)
  (sqrt-iter 1.0 x))

(sqrt 9) ; => 3.00009155413138

JavaScript

// 関数sqrt-iterは推測値guessが目的値に充分近くなるまで計算を繰り返す
function sqrt_iter(guess, x) {
    if (good_enough(guess, x))
        return guess;
    else
        return sqrt_iter(improve(guess, x), x);
}

// 関数improveは推測値guessをより良い値に改善して返す
function improve(guess, x) {
    return average(guess, x / guess);
}
// 関数averageは平均を返す
function average(x, y) {
    return (x + y) / 2;
}
// 関数good-enoughは推測値guessが十分よい値になっているかどうかを返す(今回は差が0.001より小さいかどうか)
function good_enough(guess, x) {
    return (abs(square(guess) - x) < 0.001);
}
// 関数sqrtは平方根を返す
function sqrt(x) {
    return sqrt_iter(1.0, x);
}

sqrt(9); // => 3.00009155413138

なんとなくschemeではわからなかったコードでもJavaScriptだと少しは理解できたのではないでしょうか。
次回は再帰のおはなしです。「JavaScriptでSICPを勉強する その2