Permalink
Browse files

retrofit destructuring into 'let' and 'for-each'

  • Loading branch information...
1 parent bf1e761 commit 7f41b25db34f12faaa574a08c2b3ee2e1650c47d @kumarshantanu committed Sep 9, 2012
Showing with 25 additions and 22 deletions.
  1. +1 −1 CHANGES.md
  2. +8 −13 src/quiddity/lib.clj
  3. +16 −8 test/quiddity/lib_test.clj
View
@@ -3,7 +3,7 @@
## TODO
* Destructuring primitives
-* [TODO] Retrofit destructuring into `let` `for-each`
+* Retrofit destructuring into `let` `for-each`
* [TODO] Implement `for` macro; deprecate/remove `for-each`
* [TODO] Function declaration (both `fn` and `fn*`) with destructuring
* [TODO] More macros: `if-let` `when-let` `letfn` with destructuring
View
@@ -64,7 +64,8 @@
(defn i-destructure
- "Destructure `value` into `local` and return the new environment."
+ "Destructure `value` into `local` and return a map of keywordized-symbols to
+ corresponding values."
[maps local value]
(let [ds (partial i-destructure maps)
rmm (fn [f coll & more] (reduce merge {} (apply map f coll more)))
@@ -144,11 +145,9 @@
(defn e-let
"Implementation of the `let` macro. No destructuring support."
[maps bindings & forms] {:pre [(seq bindings)
- (even? (count bindings))
- (every? symbol?
- (map first (partition 2 bindings)))]}
+ (even? (count bindings))]}
(let [[k v & more] bindings
- kv-map {(keyword k) (core/evaluate v maps)}]
+ kv-map (i-destructure maps k (core/evaluate v maps))]
(if (seq more)
(apply e-let (cons kv-map maps) more forms)
(apply e-do (cons kv-map maps) forms))))
@@ -158,19 +157,15 @@
"Basic implementation of the `for` macro, where :let, :when and :while
binding forms are not supported."
[maps bindings form] {:pre [(seq bindings)
- (even? (count bindings))
- (every? symbol?
- (map first (partition 2 bindings)))]}
+ (even? (count bindings))]}
(let [[k v & more] bindings
- realized-k (keyword k)
- realized-v (core/evaluate v maps)
- kv-map {realized-k realized-v}]
+ realized-v (core/evaluate v maps)]
(if (seq more)
(apply concat
(for [each realized-v]
- (e-for-each (cons {realized-k each} maps) more form)))
+ (e-for-each (cons (i-destructure maps k each) maps) more form)))
(for [each realized-v]
- (core/evaluate form (cons {realized-k each} maps))))))
+ (core/evaluate form (cons (i-destructure maps k each) maps))))))
(defn e-and
View
@@ -173,9 +173,7 @@
(testing "map destructuring (nested)"
(is (= (let [{{p :p} :a} {:a {:p 10}}] {:p p}) (rds "{{:keys [p]} :a}" {:a {:p 10}})) "value lookup in value lookup")
(is (= (let [{[p] :a} {:a [10]}] {:p p}) (rds "{[p] :a}" {:a [10]})) "local var (seq) in value lookup")
- (is (= (let [{{:keys [p]} :a} {:a {:p 10}}] {:p p}) (rds "{{:keys [p]} :a}" {:a {:p 10}})) ":keys lookup in value lookup"))
- (testing "nested seq/map destructuring"
- ))
+ (is (= (let [{{:keys [p]} :a} {:a {:p 10}}] {:p p}) (rds "{{:keys [p]} :a}" {:a {:p 10}})) ":keys lookup in value lookup")))
;; ---------- Equivalent of Macros ----------
@@ -325,7 +323,13 @@
(is (= 2 (es "(let [a 1] (+ 1 a) (+ x a))" {:+ + :x 1} lib/macros)) "1 var")
(is (= 3 (es "(let [a 1 b 2] (+ 1 a) (+ x b))" {:+ + :x 1} lib/macros)) "2 vars, no intra-reference")
(is (= 2 (es "(let [a 1 b a] (+ 1 a) (+ x b))" {:+ + :x 1} lib/macros)) "2 vars with direct intra-reference")
- (is (= 3 (es "(let [a 1 b (inc a)] (+ 1 a) (+ x b))" {:+ + :x 1 :inc inc} lib/macros)) "2 vars with intra-reference expr")))
+ (is (= 3 (es "(let [a 1 b (inc a)] (+ 1 a) (+ x b))" {:+ + :x 1 :inc inc} lib/macros)) "2 vars with intra-reference expr"))
+ (testing "let (destructuring)"
+ (is (= 2 (es "(let [[a] [1]] (+ 1 a) (+ x a))" {:+ + :x 1} lib/macros)) "1 local var")
+ (is (= 3 (es "(let [[a b] [1 2]] (+ 1 a) (+ x b))" {:+ + :x 1} lib/macros)) "2 local vars")
+ (is (= 2 (es "(let [{a :a} {:a 1} b a] (+ 1 a) (+ x b))" {:+ + :x 1} lib/macros)) "value lookup")
+ (is (= 3 (es "(let [{:keys [a]} {:a 1} b (inc a)] (+ 1 a) (+ x b))" {:+ + :x 1
+ :inc inc} lib/macros)) ":keys lookup")))
(deftest test-macro-equiv-for-each
@@ -336,27 +340,31 @@
(is (= (for [a [1] b [2]] 0) (es "(for-each [a [1] b [2]] 0)" lib/macros)) "2 vars, no intra-reference")
(is (= (for [a [[1]] b a] 0) (es "(for-each [a [[1]] b a] 0)" lib/macros)) "2 vars with direct intra-reference")
(is (= (for [a [[1]] b (conj a 2)] 0) (es "(for-each [a [[1]] b (conj a 2)] 0)" {:conj conj} lib/macros)) "2 vars with intra-reference expr"))
- (testing "let (single external symbol as body)"
+ (testing "for-each (single external symbol as body)"
(is (= (for [a nil] 1) (es "(for-each [a nil] x)" {:x 1} lib/macros)) "1 var over nil")
(is (= (for [a [1]] 1) (es "(for-each [a [1]] x)" {:x 1} lib/macros)) "1 var over [1]")
(is (= (for [a (range 2)] 1) (es "(for-each [a (range 2)] x)" {:range range :x 1} lib/macros)) "1 var over expr")
(is (= (for [a [1] b [2]] 1) (es "(for-each [a [1] b [2]] x)" {:x 1} lib/macros)) "2 vars, no intra-reference")
(is (= (for [a [[1]] b a] 1) (es "(for-each [a [[1]] b a] x)" {:x 1} lib/macros)) "2 vars with direct intra-reference")
(is (= (for [a [[1]] b (conj a 2)] 1) (es "(for-each [a [[1]] b (conj a 2)] x)" {:conj conj :x 1} lib/macros)) "2 vars with intra-reference expr"))
- (testing "let (single let-bound symbol as body)"
+ (testing "for-each (single let-bound symbol as body)"
(is (= (for [a nil] a) (es "(for-each [a nil] a)" lib/macros)) "1 var over nil")
(is (= (for [a [1]] a) (es "(for-each [a [1]] a)" lib/macros)) "1 var over [1]")
(is (= (for [a (range 2)] a) (es "(for-each [a (range 2)] a)" {:range range} lib/macros)) "1 var over expr")
(is (= (for [a [1] b [2]] b) (es "(for-each [a [1] b [2]] b)" lib/macros)) "2 vars, no intra-reference")
(is (= (for [a [[1]] b a] b) (es "(for-each [a [[1]] b a] b)" lib/macros)) "2 vars with direct intra-reference")
(is (= (for [a [[1]] b (conj a 2)] b) (es "(for-each [a [[1]] b (conj a 2)] b)" {:conj conj} lib/macros)) "2 vars with intra-reference expr"))
- (testing "let (single expr as body)"
+ (testing "for-each (single expr as body)"
(is (= (for [a nil] (+ 1 a)) (es "(for-each [a nil] (+ x a))" {:+ + :x 1} lib/macros)) "1 var over nil")
(is (= (for [a [1]] (+ 1 a)) (es "(for-each [a [1]] (+ x a))" {:+ + :x 1} lib/macros)) "1 var over [1]")
(is (= (for [a (range 2)] (+ 1 a)) (es "(for-each [a (range 2)] (+ x a))" {:range range :+ + :x 1} lib/macros)) "1 var over expr")
(is (= (for [a [1] b [2]] (+ 1 b)) (es "(for-each [a [1] b [2]] (+ x b))" {:+ + :x 1} lib/macros)) "2 vars, no intra-reference")
(is (= (for [a [[1]] b a] (+ 1 b)) (es "(for-each [a [[1]] b a] (+ x b))" {:+ + :x 1} lib/macros)) "2 vars with direct intra-reference")
- (is (= (for [a [[1]] b (conj a 2)] (+ 1 b)) (es "(for-each [a [[1]] b (conj a 2)] (+ x b))" {:conj conj :+ + :x 1} lib/macros)) "2 vars with intra-reference expr")))
+ (is (= (for [a [[1]] b (conj a 2)] (+ 1 b)) (es "(for-each [a [[1]] b (conj a 2)] (+ x b))" {:conj conj :+ + :x 1} lib/macros)) "2 vars with intra-reference expr"))
+ (testing "for-each (destructuring)"
+ (is (= (for [[a] [[1]]] (+ 1 a)) (es "(for-each [[a] [[1]]] (+ x a))" {:+ + :x 1} lib/macros)) "1 local var")
+ (is (= (for [[a b] [[1 2]]] (+ a b)) (es "(for-each [[a b] [[1 2]]] (+ a b))" {:+ +} lib/macros)) "2 local vars")
+ ))
(deftest test-macro-equiv-and

0 comments on commit 7f41b25

Please sign in to comment.