«بستار» یک الگوی برنامهنویسی در 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} استفاده کنید.
تابع translate2d را پیادهسازی کنید که تابعی را برمیگرداند و با استفاده از یک «بستار»، انتقال دوبعدی تکرارپذیر یک جفت مختصات را انجام میدهد.
(def move-coordinates-right-2px (translate2d 2 0))
(def result (move-coordinates-right-2px 4 8))
;; result => [6 8]
تابع scale2d را پیادهسازی کنید که تابعی را برمیگرداند و با استفاده از یک بستار، تغییر مقیاس دوبعدی تکرارپذیر یک جفت مختصات را انجام میدهد.
در این تمرین، فرض کنید مقادیر مقیاس فقط مثبتاند.
(def double-scale (scale2d 2 2))
(def result (double-scale 6 -3))
;; result => [12 -6]
دو تابع تبدیل را ترکیب کنید تا یک تبدیل تکرارپذیر انجام دهید. به این کار معمولاً ترکیب توابع میگویند که در آن نتیجهی تابع اول، '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]
تابع 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