任何错误的术语道歉 - 我对计算机科学相当陌生,我几乎只知道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
函数有一个标准的类似reduce的累加器,它只是构建表单的元素。它也有一个累加器堆栈,每次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
太OOP意义,我不确定,我基本上只熟悉Clojure。 - 我对计算机科学相当陌生,有没有与这种类型的东西有关的可访问和信息资源 - 我想我会称之为匿名的自引用(也许反身是一个更好的词?)数据结构?我还没有发现任何既平易近人又内容丰富的东西。
- 有没有更好的方法来编写
self-ish
宏?上面,我已经包含了我目前的版本,但我不能动摇这种感觉,可能有一种更简单的方法。 我对什么可能是“最明智的”实现细节有各种疑问。
- Traversal:它应该先宽度还是先深度?如果先深入,预购,后序或中序?现在,我认为这是深度优先,这对我来说很有意义,但也许它有一些我没有注意到的缺点。
秩序问题:(See here for a related previous question of mine)在
{}
这是不可能的,而无需使用array-map
或sorted-map
--in换句话说正常维持秩序(高于8映射条目),上述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
只是微不足道,但是这可能有用吗?
感谢您的阅读,任何帮助表示赞赏:)在方案
看起来很有趣给出有意义的名字,但你可以提比使事情复杂和模棱两可的其他这样的事情任何有用的用例。 – Ankur 2012-07-25 16:22:14
看起来很哲学,也许这是错误的StackExchange网站来问这个问题。 – sortega 2012-07-25 16:57:40
@Ankur好主意,我会编辑包含一个用例。这并不是说它扩展了任何功能,它可能使编写代码更直接/模块化。老实说,我不确定这是否真的值得添加模糊性或复杂性,正如你指出的那样。那正是我想要解决我的第一个问题,我也应该编辑它。 – 2012-07-25 20:17:48