用于封装的Clojure对象和高阶函数

Ral*_*lph 2 encapsulation clojure higher-order-functions

这是我之前的问题的后续行动.

我在阅读Let Over Lambda时想出了一个奇怪的对象方案,可以想到没有协议的优点,但想得到意见.我只是在探索高阶函数和封装的使用.

(defn new-person
  "Construct a new Person object and return a Map of accessor methods."
  [init-first-name init-last-name init-age]
  (let [first-name (ref init-first-name)
        last-name (ref init-last-name)
        age (ref init-age)]
    {:get-first-name #(@first-name)
     :set-first-name #(dosync (ref-set first-name %1))
     :get-last-name #(@last-name)
     :set-last-name #(dosync (ref-set last-name %1))
     :get-age #(@age)
     :set-age #(dosync (ref-set age %1))}))
Run Code Online (Sandbox Code Playgroud)

我可以使用这样的对象:

(def fred (new-person "fred" "flintstone" 42))
Run Code Online (Sandbox Code Playgroud)

并以这种方式检索访问器方法:

(fred :get-age)
Run Code Online (Sandbox Code Playgroud)

但我无法弄清楚如何调用访问器.

创建的对象是线程安全的,因为"实例"变量的所有变异都发生在STM中.

更新:新的和改进的版本:

(defn new-person
  "Construct a new Person object and return a Map of accessor methods."
  [init-first-name init-last-name init-age]
  (let [first-name (ref init-first-name)
        last-name (ref init-last-name)
        age (ref init-age)]
    {:first-name 
        (fn
          ([] @first-name)
          ([val] (dosync (ref-set first-name val))))
     :last-name
        (fn
          ([] @last-name)
          ([val] (dosync (ref-set last-name val))))
     :age
        (fn
          ([] @age)
          ([val] (dosync (ref-set age val))))}))
Run Code Online (Sandbox Code Playgroud)

Mau*_*ijk 5

也许不是你的问题的100%答案,但你会尝试做的不是Clojure非常惯用."标准"解决方案如下:

(defrecord Person [first-name last-name age])
(def fred (Person. "fred" "flintstone" 42))
(fred :age)
Run Code Online (Sandbox Code Playgroud)

看起来你强迫OO可变状态进入Clojure'对象'