对于任何错误的术语道歉 - 我很新的计算机科学,我几乎只知道Clojure的(但我想我会说我知道这非常好)。
所以,我没有做过一吨的这个研究,但我有时会发现它有用的时候写的Clojure代码可以参考一些“的任何数据结构,我在中间版本”从数据结构中(很像在let
)。 简单的例子:
=> (self-ish {:a 10
:b (inc (this :a))
:c (count (vals this))})
=> {:a 10, :b 11, :c 3}
=> (self-ish ["a" "b" (reduce str this)])
=> ["a" "b" "ab"]
//Works in any nested bits too
=> (self-ish [1 2 3 [4 5 (first this)] 6 [7 [8 (cons (second this) (nth this 3))]]])
=> [1 2 3 [4 5 1] 6 [7 [8 (2 4 5 1)]]]
我们的想法是,该结构建立起来本身递增,并在任何阶段必须参考当前中间结构的能力this
。 下面是我当前执行的代码:
//Random straightforward but helpful definitions
(defn map-entry? [obj]
(instance? clojure.lang.AMapEntry obj))
(def Map clojure.lang.IPersistentMap)
(def Vector clojure.lang.IPersistentVector)
(def List clojure.lang.IPersistentList)
(def Set clojure.lang.IPersistentSet)
(defn append
[x coll]
(if-not coll x
(condp instance? coll
Map (if (empty? x) coll
(assoc coll (first x) (second x)))
Vector (conj coll x)
Set (conj coll x)
List (apply list (concat coll [x]))
(concat coll [x]))))
(defn build-this
[acc-stack acc]
(->> (cons acc acc-stack)
(drop-while list?)
(drop-while (every-pred empty? identity))
(reduce append)))
(defn self-indulge
[acc-stack acc form]
;//Un-comment the following to see it print intermediate stages of processing
#_(println "this:" (build-this acc-stack acc) "\n at:" form)
(append (cond
(coll? form) (reduce (partial self-indulge (cons acc acc-stack))
(if (map-entry? form) []
(empty form))
form)
(= (quote this) form) (build-this acc-stack acc)
:else form)
acc))
(defmacro self-ish
[form]
(self-indulge () nil form))
该append
功能追加一个项目到收集并返回相同类型的集合。 所述self-indulge
功能有一个标准的降低状累加器,它只是积聚形式的元件。 它也有一个蓄电池组,其变长,每次self-indulge
复发自身。 这样做的一点是要保持跟踪等“高级别”蓄电池,使this
将是整个结构,而不仅仅是一个局部的一块。 该self-ish
宏观只是很好地包装了self-indulge
(使用自诩为partial
,所以它不能穿的裤子宏)。
编辑:例如用例对我来说,这个宏是关于设法提高代码的可读性,不是真正的扩展功能。 当我发现这个有用的是在我有部分冗余数据手写结构的情况下 - 或许“依赖”是一个更好的词。 它可以更容易阅读的代码,看看数据结构保持的不同部分,而且还可以,如果我修改数据值结构的一个组成部分,并希望这种改变在其他地方反映是有用的。 例如:
=> (self-ish {:favorite-books (list "Crime and Punishment" "Mrs. Dalloway")
:favorite-things (list* "Ice Cream" "Hammocks" (this :favorite-books)})
=> {:favorite-things ("Ice Cream" "Hammocks" "Crime and Punishment" "Mrs. Dalloway"),
:favorite-books ("Crime and Punishment" "Mrs. Dalloway")}
它也可能是有用的时候,其中一个可能会很喜欢的东西包括烤成的数据,而不是衍生有关使用某些功能的飞行。 这些案件可能是非常罕见的,我认为这是一个坏主意不必要的纠结中的数据时,你可能只是有很好的清洁功能,操纵它。
我的主要问题:
- 这是真正有用的,不然会含糊/复杂性招致太多? 我想我不是一个人在想/使用这种类型的宏。 什么这里有别人的经验? 你使用这样的事情? 你有没有发现更好的解决方法? 有没有考虑这样的事情是不以任何Clojure库? 或者是有什么,我还没有看到?
- 有没有我可以使用更好的命名规则-而不是
self-ish
和this
? 例如,也许this
是装过用面向对象的意思,我不知道,我基本上只熟悉使用Clojure。 - 我非常新的计算机科学,是否有相关的这种类型的东西访问和信息资源 - 我想我会称之为匿名的自我指涉(也许是反身一个更好的词?)数据结构? 我还没有发现任何东西都平易近人和信息呢。
- 有没有更好的方式来写的
self-ish
宏? 以上,我已经包括我目前它的版本,但我不能动摇的感觉有可能是一个更简单的方法。 我有什么可能是“最聪明”的实施细节的各种问题。
- 穿越 :它应该是广度优先或深度第一? 如果深度优先,序,后序,或序? 现在,我相信这是深度优先序,这对我来说很有意义,但也许有一些缺点我都没有注意到。
订单问题 :( 在这里看到我的相关前面的问题 )在
{}
即手写地图),这是不可能的,而无需使用正确维护秩序(高于8映射条目)array-map
或sorted-map
--in换句话说以上8个映射条目,{}
用法是不安全的。 也许的,而不是手写的顺序,宏可以做一些花哨的魔法来处理一些“理想的”订单项目? 或许这将是更好的包裹内的所有地图(array-map ...)
而不是赏心悦目的{}
//Showing maps with 9 entries failing => (self-ish {:a 1 :b (inc (this :a)) :c (inc (this :b)) :d (inc (this :c)) :e (inc (this :d)) :f (inc (this :e)) :g (inc (this :f)) :h (inc (this :g)) :i (inc (this :h))}) => NullPointerException clojure.lang.Numbers.ops (Numbers.java:942) //8 works fine => (self-ish {:a 1 :b (inc (this :a)) :c (inc (this :b)) :d (inc (this :c)) :e (inc (this :d)) :f (inc (this :e)) :g (inc (this :f)) :h (inc (this :g))}) => {:h 8, :g 7, :f 6, :e 5, :d 4, :c 3, :b 2, :a 1}
串行 :正如我写它,宏避免了对付它的元素串联,类似于无限递归
let
,但这并产生潜在的古怪行为。 例如,在我的上述简单的例子,(reduce str this)
返回"ab"
,因为this
是["a" "b"]
在该步骤。 也许这将是有益的,有时创建某种无限慵懒的序列呢? 如果是这样,怎么可能是实施?- 地图项 :现在,映射条目被当作载体,但由于如何
this
可以在任何中间步骤被调用,这是完全可能得到一个nil
,从有“尚未”被分配值的键值。 这就是为什么在我的第一个简单的例子,:c
最终映射到3 -因为中间有一个nil
对应:c
,并得到了计算在内。 你觉得这是值得修复? - 非宏实用程序 :这将是微不足道的使用只是
self-indulge
的宏观背景之外,但是这可能永远是有用的?
感谢您的阅读,任何帮助表示赞赏:)