任何錯誤的術語道歉 - 我對計算機科學相當陌生,我幾乎只知道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