SICPの演習をClojureでやってみた。その1

2021-06-09

入門してはフェードアウトしているClojure。

SICP本を手に入れたので、何度目かのClojure入門をしてみましました。

環境は、repl.it の Clojure 1.8.0 です。

問題 1.3

3つの数を引数としてとり、大きい2つの数の二乗の和を返す手続きを定義せよ。

(defn sum-of-squares [a b c]
  (let [[x y] (reverse (sort [a b c]))]
    (+ (* x x) (* y y))))

(sum-of-squares 3 1 2)
=> 13

(defn sum-of-squares2 [a b c]
  (->> [a b c]
      sort
      (drop 1)
      (map #(* % %))
      (reduce +)))

(sum-of-squares2 3 1 2)
=> 13

後者のほうが、Clojureぽいのかな?

問題 1.4

われわれの評価モデルは、演算子が合成式である組み合わせでもつかえることを観察せよ。

(def a-plus-abs-b [a b]
  ((if (> b 0) + -) a b)))

(a-plus-abs-b 1 2)
=> 3
(a-plus-abs-b 1 -2)
=> 3

「+」も「ー」も関数なので、これができてあたりまえなんだけど、違和感あります。

問題 1.5

Benは、彼の対面している解釈系が、作用的順序の評価を使っているか、正規順序の評価を使っているか決定するテストを発明した。次の2つの手続きを定義した。

それぞれどのような振る舞いをするか?

(defn p []
  (p))

(defn test [x y]
  (if (= x 0)
    0
    y))

(test 0 (p))

「完全に展開し、簡約する」のが、正規順序の評価。
「引数を評価し、作用させる」のが、作用的順序の評価。

(p)を評価すると、無限に再帰する。
(if)は、特殊形式?短絡評価?だから、xが0のとき、yは評価されない。

作用的順序の評価だと、(test 0 (p))の時点で、無限再帰になる。

正規順序の評価だと、(p)は評価されないので、0が返ってくる。

Clojureで試すと、「StackOverflowError」が発生。無限シーケンスが使えるので「Clojureは、遅延評価」だと勘違いしていた。作用的順序の評価で、遅延シーケンスを使うときだけ評価が遅延されているということ?

repl.it の Scheme(BiwaScheme 0.6.4) で実行してみたら、無反応になりました。こちらも、作用的順序の評価のよう。

↓要調査