座標変換

座標変換

学習演習

はじめに

クロージャは、Clojureにおけるプログラミングのパターンのひとつで、外側のレキシカルスコープにある変数を関数の内部で使えるようにするものです。Clojureはクロージャを意識させずにサポートしているので、それが何なのかを知らないまま使われることもよくあります。

;; Top-level definitions are global-scope
(def dozen 12)

;; Functions create a new scope.
;; Referencing the outer variable here is a closure.
(fn [n] (* dozen n))

状態を保存し、値を受け渡すクロージャ

アトムを使うと、ある程度の状態を保持できます。

;; This function closure increments the counter's state
;; in the outer lexical context.
;; This way the counter can be shared between many calling contexts.

(def increment
  (let [counter (atom 0)]
    (fn [] (swap! counter inc))))

incrementを呼び出すたびに、そのカウンターが1つずつ増えていきます。

(increment)
;;=> 1
(increment)
;;=> 2

説明

あなたのデザイン会社では、これまで主にCSSの変換を使ってWebページを作ってきました。いくつか話し合った結果、動的な計算にClojureを使い始めることになりました。チームメイトの中にはClojureの経験が浅い人もいるので、関数クロージャーを使って、{x, y}の座標ペアを繰り返し変換できる仕組みを作ることにします。

1. 座標を変換する

translate2d関数を実装しましょう。この関数は、クロージャーを利用して、座標ペアの2次元平行移動を繰り返し行える関数を返します。

(def move-coordinates-right-2px (translate2d 2 0))
(def result (move-coordinates-right-2px 4 8))
;; result => [6 8]

2. 座標を拡大縮小する

scale2d関数を実装しましょう。この関数は、クロージャーを利用して、座標ペアの2次元の拡大縮小を繰り返し行える関数を返します。

この演習では、拡大縮小の値は正の値のみを想定します。

(def double-scale (scale2d 2 2))
(def result (double-scale 6 -3))
;; result => [12 -6]

3. 変換関数を組み合わせる

2つの変換関数を組み合わせて、繰り返し行える変換を作りましょう。これは_関数合成_と呼ばれることが多く、1つ目の関数_'f(x)'の結果を、2つ目の関数'g(x)'_への入力として使います。

(def move-coordinates-right-2px (translate2d 2 0))
(def double-coordinates (scale2d 2 2))
(def composed-transformations 
  (compose-transform move-coordinates-right-2px 
                     double-coordinates))
(def result (composed-transformations 0 1))
;; result => [4 2]

4. 関数の結果を保存する

memoize-transform関数を実装しましょう。この関数は、_メモ化_したい関数を受け取り、その関数への入力を覚えている新しい関数を返します。こうすることで、同じ引数でもう一度呼び出されたときには、最後の戻り値を「覚えている」ので、計算は一度だけで済みます。

メモ化は_動的計画法_と呼ばれることもあり、結果が覚えられているので、コストの高い処理を一度だけ実行できるようにします。

(def triple-scale (scale2d 3 3))
(def memoized-scale (memoize-transform triple-scale))

(memoized-scale 4 3)
;; => [12, 9], this is computed since it hasn't been computed before for the arguments

(memoized-scale 4 3)
;; => [12, 9], this is remembered, since it was computed already
GitHubで編集する リンクは新しいウィンドウまたはタブで開きます
Clojure Exercism

座標変換を始める準備はできましたか?

Exercismに登録すれば、12個のコンセプト105個の演習、そして本物の人間によるメンタリングとともに、Clojureを学んでマスターできます。すべて無料です。