Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 129 lines (107 sloc) 4.221 kb
169290b @richhickey made copyright notices uniform
richhickey authored
1 ; Copyright (c) Rich Hickey. All rights reserved.
2 ; The use and distribution terms for this software are covered by the
3 ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
4 ; which can be found in the file epl-v10.html at the root of this distribution.
5 ; By using this software in any fashion, you are agreeing to be bound by
6 ; the terms of this license.
7 ; You must not remove this notice, or any other, from this software.
8
d5f4c4c @stuarthalloway gtic work-in-progress:
stuarthalloway authored
9 ;;; walk.clj - generic tree walker with replacement
10
169290b @richhickey made copyright notices uniform
richhickey authored
11 ;; by Stuart Sierra
d5f4c4c @stuarthalloway gtic work-in-progress:
stuarthalloway authored
12 ;; December 15, 2008
13
14 ;; CHANGE LOG:
15 ;;
16 ;; * December 15, 2008: replaced 'walk' with 'prewalk' & 'postwalk'
17 ;;
18 ;; * December 9, 2008: first version
19
20
21 (ns
7879383 @richhickey replace #^s with ^s
richhickey authored
22 ^{:author "Stuart Sierra",
d5f4c4c @stuarthalloway gtic work-in-progress:
stuarthalloway authored
23 :doc "This file defines a generic tree walker for Clojure data
24 structures. It takes any data structure (list, vector, map, set,
25 seq), calls a function on every element, and uses the return value
26 of the function in place of the original. This makes it fairly
27 easy to write recursive search-and-replace functions, as shown in
28 the examples.
29
30 Note: \"walk\" supports all Clojure data structures EXCEPT maps
31 created with sorted-map-by. There is no (obvious) way to retrieve
32 the sorting function."}
a12092c @stuarthalloway gtic package renamings:
stuarthalloway authored
33 clojure.walk)
d5f4c4c @stuarthalloway gtic work-in-progress:
stuarthalloway authored
34
35 (defn walk
36 "Traverses form, an arbitrary data structure. inner and outer are
37 functions. Applies inner to each element of form, building up a
38 data structure of the same type, then applies outer to the result.
c567308 @timothypratley Added sorted-by support for walk and tests
timothypratley authored
39 Recognizes all Clojure data structures. Consumes seqs as with doall."
40
c1c3916 @stuarthalloway metadata for :added
stuarthalloway authored
41 {:added "1.1"}
d5f4c4c @stuarthalloway gtic work-in-progress:
stuarthalloway authored
42 [inner outer form]
43 (cond
44 (list? form) (outer (apply list (map inner form)))
c567308 @timothypratley Added sorted-by support for walk and tests
timothypratley authored
45 (instance? clojure.lang.IMapEntry form) (outer (vec (map inner form)))
d5f4c4c @stuarthalloway gtic work-in-progress:
stuarthalloway authored
46 (seq? form) (outer (doall (map inner form)))
c567308 @timothypratley Added sorted-by support for walk and tests
timothypratley authored
47 (coll? form) (outer (into (empty form) (map inner form)))
d5f4c4c @stuarthalloway gtic work-in-progress:
stuarthalloway authored
48 :else (outer form)))
49
50 (defn postwalk
51 "Performs a depth-first, post-order traversal of form. Calls f on
52 each sub-form, uses f's return value in place of the original.
c567308 @timothypratley Added sorted-by support for walk and tests
timothypratley authored
53 Recognizes all Clojure data structures. Consumes seqs as with doall."
c1c3916 @stuarthalloway metadata for :added
stuarthalloway authored
54 {:added "1.1"}
d5f4c4c @stuarthalloway gtic work-in-progress:
stuarthalloway authored
55 [f form]
56 (walk (partial postwalk f) f form))
57
58 (defn prewalk
59 "Like postwalk, but does pre-order traversal."
c1c3916 @stuarthalloway metadata for :added
stuarthalloway authored
60 {:added "1.1"}
d5f4c4c @stuarthalloway gtic work-in-progress:
stuarthalloway authored
61 [f form]
62 (walk (partial prewalk f) identity (f form)))
63
64
65 ;; Note: I wanted to write:
66 ;;
67 ;; (defn walk
68 ;; [f form]
69 ;; (let [pf (partial walk f)]
70 ;; (if (coll? form)
71 ;; (f (into (empty form) (map pf form)))
72 ;; (f form))))
73 ;;
74 ;; but this throws a ClassCastException when applied to a map.
75
76
77 (defn postwalk-demo
78 "Demonstrates the behavior of postwalk by printing each form as it is
79 walked. Returns form."
c1c3916 @stuarthalloway metadata for :added
stuarthalloway authored
80 {:added "1.1"}
d5f4c4c @stuarthalloway gtic work-in-progress:
stuarthalloway authored
81 [form]
82 (postwalk (fn [x] (print "Walked: ") (prn x) x) form))
83
84 (defn prewalk-demo
85 "Demonstrates the behavior of prewalk by printing each form as it is
86 walked. Returns form."
c1c3916 @stuarthalloway metadata for :added
stuarthalloway authored
87 {:added "1.1"}
d5f4c4c @stuarthalloway gtic work-in-progress:
stuarthalloway authored
88 [form]
89 (prewalk (fn [x] (print "Walked: ") (prn x) x) form))
90
91 (defn keywordize-keys
92 "Recursively transforms all map keys from strings to keywords."
c1c3916 @stuarthalloway metadata for :added
stuarthalloway authored
93 {:added "1.1"}
d5f4c4c @stuarthalloway gtic work-in-progress:
stuarthalloway authored
94 [m]
95 (let [f (fn [[k v]] (if (string? k) [(keyword k) v] [k v]))]
96 ;; only apply to maps
97 (postwalk (fn [x] (if (map? x) (into {} (map f x)) x)) m)))
98
99 (defn stringify-keys
100 "Recursively transforms all map keys from keywords to strings."
c1c3916 @stuarthalloway metadata for :added
stuarthalloway authored
101 {:added "1.1"}
d5f4c4c @stuarthalloway gtic work-in-progress:
stuarthalloway authored
102 [m]
103 (let [f (fn [[k v]] (if (keyword? k) [(name k) v] [k v]))]
104 ;; only apply to maps
105 (postwalk (fn [x] (if (map? x) (into {} (map f x)) x)) m)))
106
107 (defn prewalk-replace
108 "Recursively transforms form by replacing keys in smap with their
109 values. Like clojure/replace but works on any data structure. Does
110 replacement at the root of the tree first."
c1c3916 @stuarthalloway metadata for :added
stuarthalloway authored
111 {:added "1.1"}
d5f4c4c @stuarthalloway gtic work-in-progress:
stuarthalloway authored
112 [smap form]
113 (prewalk (fn [x] (if (contains? smap x) (smap x) x)) form))
114
115 (defn postwalk-replace
116 "Recursively transforms form by replacing keys in smap with their
117 values. Like clojure/replace but works on any data structure. Does
118 replacement at the leaves of the tree first."
c1c3916 @stuarthalloway metadata for :added
stuarthalloway authored
119 {:added "1.1"}
d5f4c4c @stuarthalloway gtic work-in-progress:
stuarthalloway authored
120 [smap form]
121 (postwalk (fn [x] (if (contains? smap x) (smap x) x)) form))
122
123 (defn macroexpand-all
124 "Recursively performs all possible macroexpansions in form."
c1c3916 @stuarthalloway metadata for :added
stuarthalloway authored
125 {:added "1.1"}
d5f4c4c @stuarthalloway gtic work-in-progress:
stuarthalloway authored
126 [form]
127 (prewalk (fn [x] (if (seq? x) (macroexpand x) x)) form))
128
Something went wrong with that request. Please try again.