feat: add walk* (#1134)

This commit is contained in:
Veit Heller 2021-01-17 23:34:11 +01:00 committed by GitHub
parent dd81164f93
commit e966f36a58
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 87 additions and 0 deletions

View File

@ -238,4 +238,68 @@
'()
l))
(doc walk "traverses `form`, an arbitrary data structure, using the functions
`inner` and `outer`. It will apply `inner` to each element of `form`, building
up a data structure of the same type, then applies `outer` to the result. It
recognizes arrays and lists. Other data structures will just be passed to
`outer`.
Example:
```
(walk car reverse [[1 2] [3 4] [5 6]]) ; => [5 3 1]
```")
(defndynamic walk [inner outer form]
(cond
(list? form) (outer (map inner form))
(array? form) (outer (collect-into (map inner form) array))
(outer form)))
(doc postwalk "Performs a depth-first, post-order traversal of `form` and
calls `f` on each subform, collecting the result.
Example:
```
; note: this could be achieved using `walk-replace` as well
(postwalk (fn [x]
(cond
(= x '+) '*
(= x '-) '/
x))
'(+ 1 (- 2 3))) ; => (* 1 (/ 2 3))
```")
(defndynamic postwalk [f form]
(walk (curry postwalk f) f form))
(doc prewalk "behaves like [`postwalk`](#postwalk), but does pre-order
traversal.
Example:
```
(prewalk (fn [x] (if (number? x) (* x 4) x)) '(+ 1 (- 2 3))) ; => (+ 4 (- 8 12))
```")
(defndynamic prewalk [f form]
(walk (curry prewalk f) (fn [x] x) (f form)))
(hidden walk-replace-finder)
(defndynamic walk-replace-finder [p el]
(if (empty? p)
p
(let [f (car p)]
(if (= (car f) el)
f
(walk-replace-finder (cdr p) el)))))
(doc walk-replace "Performs a depth-first, pre-order traversal of `form` and
finds a matching replacement for each subform in the replacement pairs `pairs`,
if applicable, collecting the result.
Example:
```
(walk-replace '((+ *) (- /)) '(+ 1 (- 2 3))) ; => (* 1 (/ 2 3))
```")
(defndynamic walk-replace [pairs form]
(prewalk (fn [x]
(let [r (walk-replace-finder pairs x)]
(if (empty? r) x (cadr r))))
form))
)

View File

@ -131,6 +131,17 @@
`(+ %global-x
(+ %@(map inc [1 2]))))
(defmacro test-postwalk []
(eval (postwalk (fn [x] (if (= x '+) '* x))
'(+ 2 (+ 2 3)))))
(defmacro test-prewalk []
(eval (prewalk (fn [x] (if (= x '+) '* x))
'(+ 2 (+ 2 3)))))
(defmacro test-walk-replace []
(eval (walk-replace '((+ *)) '(+ 2 (+ 2 3)))))
(deftest test
(assert-true test
@ -355,4 +366,16 @@
6
(test-quasiquote-reader)
"quasiquote reader works as expected")
(assert-equal test
12
(test-postwalk)
"postwalk works as expected")
(assert-equal test
12
(test-prewalk)
"prewalk works as expected")
(assert-equal test
12
(test-walk-replace)
"walk-replace works as expected")
)