轨道
/
Clojure
Clojure
/
练习
/
坐标变换
坐标变换

坐标变换

学习练习

简介

闭包是一种 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))

用闭包保存状态并传递值

使用 atom 可以保留一部分状态:

;; 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,它的计数器就会自增:

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

说明

你的设计公司一直主要使用 CSS 变换来构建网页。经过一番讨论,公司决定开始使用 Clojure 来动态执行一些计算。你的一些队友对 Clojure 不太熟悉,因此你决定使用函数闭包,为{x, y}坐标对创建可复用的变换。

1. 平移坐标

实现translate2d函数。它返回一个函数,该函数利用闭包,对坐标对执行可重复的二维平移。

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

2. 缩放坐标

实现scale2d函数。它返回一个函数,该函数利用闭包,对坐标对执行可重复的二维缩放。

在本练习中,假设缩放值均为正数。

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

3. 组合变换函数

组合两个变换函数,执行可重复的变换。这通常称为_函数组合_:第一个函数 'f(x)' 的结果会作为第二个函数 '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,全部免费。