おたっく's blog

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

JavaScriptでSICPを勉強する その3

JavaScriptSICPを勉強する その3」です。

1.3 高階手続きによる抽象 (p.31)


例えば
f:id:otaks:20121216125059g:plain
という計算がしたいときは関数を引数に取る関数sigmaを定義するとよいでしょう。
scheme

(define (sigma a b f)
  (if (> a b)
      0
      (sigma (f a) b sigma)))

(define (f x) (* x x))
(define (g x) (* 2 x))
(sigma 1 3 f) ; => 14 (1 + 4 + 9)
(sigma 1 3 g) ; => 12 (2 + 4 + 6)

JavaScript

function sigma(a, b, f) {
    if (a > b)
        return 0;
    else
        return sigma(a+1, b, f);
}
function f(x) {
    return x * x;
}
function g(x) {
    return 2 * x;
}

sigma(1, 3, f); // => 14 (1 + 4 + 9)
sigma(1, 3, g); // => 12 (2 + 4 + 6)

このように関数を引数に取る関数のことを高階関数(higher-order function)といいます。高階関数は数学の世界では汎関数と呼ばれているようです。

1.3.2 lambdaを使う手続きの構築 (p.34)


schemeではlambdaは次のような書式で書きます。

(lambda (<引数の並び>) (<関数本体>))

これに対応するJavaScriptのコードは以下のようになります。

function (<引数の並び>) {<関数本体>}


lambdaを使って試しに数値を4増やして返す関数plus4というのを作ってみましょう。

scheme

(define plus4 (lambda (x) (+ x 4)))

JavaScript

var plus4 = function (x) {return x + 4;};

局所変数を創りだすletの使い方 (p.35)


また局所変数を使いたいときに便利なletというものがあります。書式は次のようになっています。

(let ((<変数名> <束縛する値>)
      (<変数名> <束縛する値>)
      ...
      (<変数名> <束縛する値>))
  <本体>

束縛する変数は複数書くことができます。ちなみにletは次のシンタックスシュガー(構文糖)にすぎません。

((lambda (<変数1>...<変数n>)
         <本体>)
  <束縛する値1>
  ...
  <束縛する値n>)

例えば2点間の距離を返す関数をつくり、その中でletを使ってみましょう。

(define (dist x1 y1 x2 y2)
  (let ((x (- x1 x2))
        (y (- y1 y2)))
    (sqrt (+ (* x x) (* y y)))))

(dist 0 0 1 1) ; => 1.4142135623730951

今回は高階手続きによる抽象をやりました。次回はcar, cdr, consやlistのおなはしで「JavaScriptでSICPを勉強する その4」です。