使用概率字段统一访问Clojure记录

mac*_*mac 2 records clojure

是否有一种优雅的方式来创建和使用具有常量和概率字段的记录.我希望能够做类似下面的事情,其中​​"sampler"是一个从某个分布返回样本的函数.目标是使用户无论访问的字段是常量还是概率都是透明的.

> (defrecord Stat [val1 val2])

> (def s1 (Stat. 1 sampler))

> (:val1 s1)

> 1

> (:val2 s1)

> 4

> (:val2 s1)

> 2
Run Code Online (Sandbox Code Playgroud)

ama*_*loy 8

对于自定义deftypes,关键字查找的行为可能不仅仅是在地图中查找固定值,但我强烈建议不要使用它.它不仅需要做很多工作,还会违背每个人阅读代码的期望.

但是,稍微调整一下您的要求就可以得到一个简单的解决方案:而不是(:val1 x)(x :val1).现在x可以简单地成为一个函数,它让它接收的输入决定了它的行为:

user> (defn stat [distributions]
        (fn [sample]
          ((get distributions sample))))

#'user/stat
user> (def s1 (stat {:val1 (constantly 1)
                     :val2 #(rand-int 5)}))
#'user/s1
user> (s1 :val1)
1
user> (s1 :val2)
3
user> (s1 :val2)
4
Run Code Online (Sandbox Code Playgroud)


Bey*_*mor 6

定义的记录的查找行为defrecord无法更改.deftype提供更多控制,但实现所有正确的接口需要一些工作.意识到,potemkin可以让您轻松定义具有自定义行为的类似地图的事物:

(use '[potemkin :only [def-map-type]])

(def-map-type Stat [val1 val2]
              (get [_ k default-value]
                   (case k
                     :val1  val1
                     :val2  (val2)
                     default-value)))

(def s1 (->Stat 1 #(rand-int 10)))

(:val1 s1) ; => 1
(:val2 s1) ; => something in [0, 9]
(get s1 :val2) ; => something in [0, 9]
Run Code Online (Sandbox Code Playgroud)

您也可以定义assoc,dissoc以及keys但是他们有意义的数据.