From 99638ba2df39f6c2db8b05d0504289b487daa354 Mon Sep 17 00:00:00 2001 From: Kodi Arfer Date: Fri, 3 Feb 2017 17:03:06 -0800 Subject: [PATCH 1/8] Remove uses of `let` from /hy --- hy/contrib/botsbuildbots.hy | 6 ++-- hy/contrib/loop.hy | 24 +++++++-------- hy/core/language.hy | 61 ++++++++++++++++++------------------- hy/core/macros.hy | 48 ++++++++++++++--------------- hy/core/shadow.hy | 36 +++++++++++----------- hy/extra/anaphoric.hy | 59 +++++++++++++++++++---------------- 6 files changed, 120 insertions(+), 114 deletions(-) diff --git a/hy/contrib/botsbuildbots.hy b/hy/contrib/botsbuildbots.hy index fcea8c6..1e96b66 100644 --- a/hy/contrib/botsbuildbots.hy +++ b/hy/contrib/botsbuildbots.hy @@ -26,8 +26,8 @@ (do (import [requests]) - (let [r (requests.get - "https://raw.githubusercontent.com/hylang/hy/master/AUTHORS")] - (repeat r.text))) + (setv r (requests.get + "https://raw.githubusercontent.com/hylang/hy/master/AUTHORS")) + (repeat r.text)) (except [e ImportError] (repeat "Botsbuildbots requires `requests' to function.")))) diff --git a/hy/contrib/loop.hy b/hy/contrib/loop.hy index d114140..40217d6 100644 --- a/hy/contrib/loop.hy +++ b/hy/contrib/loop.hy @@ -58,13 +58,13 @@ (defmacro/g! fnr [signature &rest body] - (let [new-body (recursive-replace 'recur g!recur-fn body)] - `(do - (import [hy.contrib.loop [--trampoline--]]) - (with-decorator - --trampoline-- - (def ~g!recur-fn (fn [~@signature] ~@new-body))) - ~g!recur-fn))) + (setv new-body (recursive-replace 'recur g!recur-fn body)) + `(do + (import [hy.contrib.loop [--trampoline--]]) + (with-decorator + --trampoline-- + (def ~g!recur-fn (fn [~@signature] ~@new-body))) + ~g!recur-fn)) (defmacro defnr [name lambda-list &rest body] @@ -86,8 +86,8 @@ ;; If recur is used in a non-tail-call position, None is returned, which ;; causes chaos. Fixing this to detect if recur is in a tail-call position ;; and erroring if not is a giant TODO. - (let [fnargs (map (fn [x] (first x)) bindings) - initargs (map second bindings)] - `(do (require hy.contrib.loop) - (hy.contrib.loop.defnr ~g!recur-fn [~@fnargs] ~@body) - (~g!recur-fn ~@initargs)))) + (setv fnargs (map (fn [x] (first x)) bindings) + initargs (map second bindings)) + `(do (require hy.contrib.loop) + (hy.contrib.loop.defnr ~g!recur-fn [~@fnargs] ~@body) + (~g!recur-fn ~@initargs))) diff --git a/hy/core/language.hy b/hy/core/language.hy index 5628e3f..54f24d8 100644 --- a/hy/core/language.hy +++ b/hy/core/language.hy @@ -103,13 +103,12 @@ (defn distinct [coll] "Return a generator from the original collection with duplicates removed" - (let [seen (set) - citer (iter coll)] + (setv seen (set) citer (iter coll)) (for* [val citer] (if (not_in val seen) (do (yield val) - (.add seen val)))))) + (.add seen val))))) (if-python2 (def @@ -178,9 +177,9 @@ (defn drop-last [n coll] "Return a sequence of all but the last n elements in coll." - (let [iters (tee coll)] - (map first (apply zip [(get iters 0) - (drop n (get iters 1))])))) + (setv iters (tee coll)) + (map first (apply zip [(get iters 0) + (drop n (get iters 1))]))) (defn empty? [coll] "Return True if `coll` is empty" @@ -229,14 +228,14 @@ (setv _gensym_lock (Lock)) (defn gensym [&optional [g "G"]] - (let [new_symbol None] - (global _gensym_counter) - (global _gensym_lock) - (.acquire _gensym_lock) - (try (do (setv _gensym_counter (inc _gensym_counter)) - (setv new_symbol (HySymbol (.format ":{0}_{1}" g _gensym_counter)))) - (finally (.release _gensym_lock))) - new_symbol)) + (setv new_symbol None) + (global _gensym_counter) + (global _gensym_lock) + (.acquire _gensym_lock) + (try (do (setv _gensym_counter (inc _gensym_counter)) + (setv new_symbol (HySymbol (.format ":{0}_{1}" g _gensym_counter)))) + (finally (.release _gensym_lock))) + new_symbol) (defn calling-module-name [&optional [n 1]] "Get the name of the module calling `n` levels up the stack from the @@ -335,16 +334,16 @@ from the latter (left-to-right) will be combined with the mapping in the result by calling (f val-in-result val-in-latter)." (if (any maps) - (let [merge-entry (fn [m e] - (let [k (get e 0) - v (get e 1)] - (if (in k m) - (assoc m k (f (get m k) v)) - (assoc m k v))) - m) - merge2 (fn [m1 m2] - (reduce merge-entry (.items m2) (or m1 {})))] - (reduce merge2 maps)))) + (do + (defn merge-entry [m e] + (setv k (get e 0) v (get e 1)) + (if (in k m) + (assoc m k (f (get m k) v)) + (assoc m k v)) + m) + (defn merge2 [m1 m2] + (reduce merge-entry (.items m2) (or m1 {}))) + (reduce merge2 maps)))) (defn neg? [n] "Return true if n is < 0" @@ -421,13 +420,13 @@ "Return every nth member of coll raises ValueError for (not (pos? n))" (if (pos? n) - (let [citer (iter coll) - skip (dec n)] - (for* [val citer] - (yield val) - (for* [_ (range skip)] - (next citer)))) - (raise (ValueError "n must be positive")))) + (do + (setv citer (iter coll) skip (dec n)) + (for* [val citer] + (yield val) + (for* [_ (range skip)] + (next citer)))) + (raise (ValueError "n must be positive")))) (defn zero? [n] "Return true if n is 0" diff --git a/hy/core/macros.hy b/hy/core/macros.hy index b41b45a..7046296 100644 --- a/hy/core/macros.hy +++ b/hy/core/macros.hy @@ -125,8 +125,8 @@ [(empty? args) `(do ~@body ~@belse)] [(= (len args) 2) `(for* [~@args] (do ~@body) ~@belse)] [True - (let [alist (cut args 0 None 2)] - `(for* [(, ~@alist) (genexpr (, ~@alist) [~@args])] (do ~@body) ~@belse))])) + (setv alist (cut args 0 None 2)) + `(for* [(, ~@alist) (genexpr (, ~@alist) [~@args])] (do ~@body) ~@belse)])) (defmacro -> [head &rest rest] @@ -151,7 +151,8 @@ (if (isinstance expression HyExpression) `(~(first expression) ~f ~@(rest expression)) `(~expression ~f))) - `(let [~f ~form] + `(do + (setv ~f ~form) ~@(map build-form expressions) ~f)) @@ -203,23 +204,24 @@ (defmacro with-gensyms [args &rest body] (setv syms []) (for* [arg args] - (.extend syms `[~arg (gensym '~arg)])) - `(let ~syms - ~@body)) + (.extend syms [arg `(gensym '~arg)])) + `(do + (setv ~@syms) + ~@body)) (defmacro defmacro/g! [name args &rest body] - (let [syms (list + (setv syms (list (distinct (filter (fn [x] (and (hasattr x "startswith") (.startswith x "g!"))) (flatten body)))) - gensyms []] - (for* [sym syms] - (.extend gensyms `[~sym (gensym (cut '~sym 2))])) - `(defmacro ~name [~@args] - (let ~gensyms - ~@body)))) + gensyms []) + (for* [sym syms] + (.extend gensyms [sym `(gensym ~(cut sym 2))])) + `(defmacro ~name [~@args] + (setv ~@gensyms) + ~@body)) (defmacro defmacro! [name args &rest body] "Like defmacro/g! plus automatic once-only evaluation for o! @@ -251,17 +253,15 @@ (defmacro defmain [args &rest body] "Write a function named \"main\" and do the if __main__ dance" - (let [retval (gensym) - mainfn `(fn [~@args] - ~@body)] - `(when (= --name-- "__main__") - (import sys) - (setv ~retval (apply ~mainfn sys.argv)) - (if (integer? ~retval) - (sys.exit ~retval))))) + (setv retval (gensym)) + `(when (= --name-- "__main__") + (import sys) + (setv ~retval (apply (fn [~@args] ~@body) sys.argv)) + (if (integer? ~retval) + (sys.exit ~retval)))) (defreader @ [expr] - (let [decorators (cut expr None -1) - fndef (get expr -1)] - `(with-decorator ~@decorators ~fndef))) + (setv decorators (cut expr None -1) + fndef (get expr -1)) + `(with-decorator ~@decorators ~fndef)) diff --git a/hy/core/shadow.hy b/hy/core/shadow.hy index 5008973..d216b17 100644 --- a/hy/core/shadow.hy +++ b/hy/core/shadow.hy @@ -26,22 +26,22 @@ (defn + [&rest args] "Shadow + operator for when we need to import / map it against something" - (let [count (len args)] - (if (zero? count) - (raise (TypeError "Need at least 1 argument to add/concatenate")) - (if (= count 1) - (operator.pos (get args 0)) - (reduce operator.add args))))) + (if + (= (len args) 1) + (operator.pos (get args 0)) + args + (reduce operator.add args) + (raise (TypeError "Need at least 1 argument to add/concatenate")))) (defn - [&rest args] "Shadow - operator for when we need to import / map it against something" - (let [count (len args)] - (if (= count 0) - (raise (TypeError "Need at least 1 argument to subtract")) - (if (= count 1) - (- (get args 0)) - (reduce operator.sub args))))) + (if + (= (len args) 1) + (- (get args 0)) + args + (reduce operator.sub args) + (raise (TypeError "Need at least 1 argument to subtract")))) (defn * [&rest args] @@ -53,12 +53,12 @@ (defn / [&rest args] "Shadow / operator for when we need to import / map it against something" - (let [count (len args)] - (if (= count 0) - (raise (TypeError "Need at least 1 argument to divide")) - (if (= count 1) - (operator.truediv 1 (get args 0)) - (reduce operator.truediv args))))) + (if + (= (len args) 1) + (operator.truediv 1 (get args 0)) + args + (reduce operator.truediv args) + (raise (TypeError "Need at least 1 argument to divide")))) (defn comp-op [op args] diff --git a/hy/extra/anaphoric.hy b/hy/extra/anaphoric.hy index aaee36b..ac5c80e 100644 --- a/hy/extra/anaphoric.hy +++ b/hy/extra/anaphoric.hy @@ -26,8 +26,9 @@ (defmacro ap-if [test-form then-form &optional else-form] - `(let [it ~test-form] - (if it ~then-form ~else-form))) + `(do + (setv it ~test-form) + (if it ~then-form ~else-form))) (defmacro ap-each [lst &rest body] @@ -38,38 +39,44 @@ (defmacro ap-each-while [lst form &rest body] "Evaluate the body form for each element in the list while the predicate form evaluates to True." - `(let [p (lambda [it] ~form)] + (setv p (gensym)) + `(do + (defn ~p [it] ~form) (for [it ~lst] - (if (p it) + (if (~p it) ~@body (break))))) (defmacro ap-map [form lst] "Yield elements evaluated in the form for each element in the list." - (let [v (gensym 'v) - f (gensym 'f)] - `(let [~f (lambda [it] ~form)] - (for [~v ~lst] - (yield (~f ~v)))))) + (setv v (gensym 'v) f (gensym 'f)) + `((fn [] + (defn ~f [it] ~form) + (for [~v ~lst] + (yield (~f ~v)))))) (defmacro ap-map-when [predfn rep lst] "Yield elements evaluated for each element in the list when the predicate function returns True." - `(let [f (lambda [it] ~rep)] + (setv f (gensym)) + `((fn [] + (defn ~f [it] ~rep) (for [it ~lst] (if (~predfn it) - (yield (f it)) - (yield it))))) + (yield (~f it)) + (yield it)))))) (defmacro ap-filter [form lst] "Yield elements returned when the predicate form evaluates to True." - `(let [pred (lambda [it] ~form)] + (setv pred (gensym)) + `((fn [] + (defn ~pred [it] ~form) (for [val ~lst] - (if (pred val) - (yield val))))) + (if (~pred val) + (yield val)))))) (defmacro ap-reject [form lst] @@ -80,14 +87,15 @@ (defmacro ap-dotimes [n &rest body] "Execute body for side effects `n' times, with it bound from 0 to n-1" (unless (numeric? n) - (raise (TypeError (.format "{0!r} is not a number" n)))) + (raise (TypeError (.format "{!r} is not a number" n)))) `(ap-each (range ~n) ~@body)) (defmacro ap-first [predfn lst] "Yield the first element that passes `predfn`" (with-gensyms [n] - `(let [~n None] + `(do + (setv ~n None) (ap-each ~lst (when ~predfn (setv ~n it) (break))) ~n))) @@ -95,7 +103,8 @@ (defmacro ap-last [predfn lst] "Yield the last element that passes `predfn`" (with-gensyms [n] - `(let [~n None] + `(do + (setv ~n None) (ap-each ~lst (none? ~n) (when ~predfn (setv ~n it))) @@ -104,20 +113,18 @@ (defmacro ap-reduce [form lst &optional [initial-value None]] "Anaphoric form of reduce, `acc' and `it' can be used for a form" - (if (none? initial-value) - `(let [acc (car ~lst)] - (ap-each (cdr ~lst) (setv acc ~form)) - acc) - `(let [acc ~initial-value] - (ap-each ~lst (setv acc ~form)) - acc))) + `(do + (setv acc ~(if (none? initial-value) `(car ~lst) initial-value)) + (ap-each ~(if (none? initial-value) `(cdr ~lst) lst) + (setv acc ~form)) + acc)) (defmacro ap-pipe [var &rest forms] "Pushes a value through several forms. (Anaphoric version of -> and ->>)" (if (empty? forms) var - `(ap-pipe (let [it ~var] ~(first forms)) ~@(rest forms)))) + `(ap-pipe (do (setv it ~var) ~(first forms)) ~@(rest forms)))) (defmacro ap-compose [&rest forms] From d72abb39f17c607577b94f6ebd5e940431115197 Mon Sep 17 00:00:00 2001 From: Kodi Arfer Date: Sat, 4 Feb 2017 09:07:27 -0800 Subject: [PATCH 2/8] Remove uses of `let` from various tests --- tests/native_tests/contrib/walk.hy | 24 +++--- tests/native_tests/core.hy | 10 +-- tests/native_tests/defclass.hy | 6 +- tests/native_tests/extra/anaphoric.hy | 6 +- tests/native_tests/mathematics.hy | 111 +++++++++++++------------- tests/native_tests/native_macros.hy | 20 +++-- tests/native_tests/py3_only_tests.hy | 37 +++++---- tests/native_tests/shadow.hy | 96 +++++++++++----------- 8 files changed, 157 insertions(+), 153 deletions(-) diff --git a/tests/native_tests/contrib/walk.hy b/tests/native_tests/contrib/walk.hy index af4dfca..7abd520 100644 --- a/tests/native_tests/contrib/walk.hy +++ b/tests/native_tests/contrib/walk.hy @@ -15,20 +15,20 @@ walk-form))) (defn test-walk [] - (let [acc '()] - (assert (= (walk (partial collector acc) identity walk-form) - [None None])) - (assert (= acc walk-form))) - (let [acc []] - (assert (= (walk identity (partial collector acc) walk-form) - None)) - (assert (= acc [walk-form])))) + (setv acc '()) + (assert (= (walk (partial collector acc) identity walk-form) + [None None])) + (assert (= acc walk-form)) + (setv acc []) + (assert (= (walk identity (partial collector acc) walk-form) + None)) + (assert (= acc [walk-form]))) (defn test-walk-iterators [] - (let [acc []] - (assert (= (walk (fn [x] (* 2 x)) (fn [x] x) - (drop 1 [1 [2 [3 [4]]]])) - [[2 [3 [4]] 2 [3 [4]]]])))) + (setv acc []) + (assert (= (walk (fn [x] (* 2 x)) (fn [x] x) + (drop 1 [1 [2 [3 [4]]]])) + [[2 [3 [4]] 2 [3 [4]]]]))) (defn test-macroexpand-all [] (assert (= (macroexpand-all '(with [a 1 b 2 c 3] (for [d c] foo))) diff --git a/tests/native_tests/core.hy b/tests/native_tests/core.hy index 2263f53..a24a401 100644 --- a/tests/native_tests/core.hy +++ b/tests/native_tests/core.hy @@ -561,11 +561,11 @@ (setv res (list (take-nth 3 [1 2 3 None 5 6]))) (assert-equal res [1 None]) ;; using 0 should raise ValueError - (let [passed False] - (try - (setv res (list (take-nth 0 [1 2 3 4 5 6 7]))) - (except [ValueError] (setv passed True))) - (assert passed))) + (setv passed False) + (try + (setv res (list (take-nth 0 [1 2 3 4 5 6 7]))) + (except [ValueError] (setv passed True))) + (assert passed)) (defn test-take-while [] "NATIVE: testing the take-while function" diff --git a/tests/native_tests/defclass.hy b/tests/native_tests/defclass.hy index a5fbd1d..1819d6d 100644 --- a/tests/native_tests/defclass.hy +++ b/tests/native_tests/defclass.hy @@ -36,9 +36,9 @@ (+ self.x value))]) (assert (= B.x 42)) (assert (= (.y (B) 5) 47)) - (let [b (B)] - (setv B.x 0) - (assert (= (.y b 1) 1)))) + (setv b (B)) + (setv B.x 0) + (assert (= (.y b 1) 1))) (defn test-defclass-dynamic-inheritance [] diff --git a/tests/native_tests/extra/anaphoric.hy b/tests/native_tests/extra/anaphoric.hy index f2253d3..2c0b73a 100644 --- a/tests/native_tests/extra/anaphoric.hy +++ b/tests/native_tests/extra/anaphoric.hy @@ -59,7 +59,7 @@ [3 6 9]) (assert-equal (list (ap-map (* it 3) [])) []) - (assert-equal (let [v 1 f 1] (list (ap-map (it v f) [(fn [a b] (+ a b))]))) + (assert-equal (do (setv v 1 f 1) (list (ap-map (it v f) [(fn [a b] (+ a b))]))) [2])) (defn test-ap-map-when [] @@ -83,9 +83,9 @@ (defn test-ap-dotimes [] "NATIVE: testing anaphoric dotimes" - (assert-equal (let [n []] (ap-dotimes 3 (.append n 3)) n) + (assert-equal (do (setv n []) (ap-dotimes 3 (.append n 3)) n) [3 3 3]) - (assert-equal (let [n []] (ap-dotimes 3 (.append n it)) n) + (assert-equal (do (setv n []) (ap-dotimes 3 (.append n it)) n) [0 1 2])) (defn test-ap-first [] diff --git a/tests/native_tests/mathematics.hy b/tests/native_tests/mathematics.hy index 5ab90c4..dcca54e 100644 --- a/tests/native_tests/mathematics.hy +++ b/tests/native_tests/mathematics.hy @@ -81,75 +81,75 @@ (defn test-augassign-add [] "NATIVE: test augassign add" - (let [x 1] - (+= x 41) - (assert (= x 42)))) + (setv x 1) + (+= x 41) + (assert (= x 42))) (defn test-augassign-sub [] "NATIVE: test augassign sub" - (let [x 1] - (-= x 41) - (assert (= x -40)))) + (setv x 1) + (-= x 41) + (assert (= x -40))) (defn test-augassign-mult [] "NATIVE: test augassign mult" - (let [x 1] - (*= x 41) - (assert (= x 41)))) + (setv x 1) + (*= x 41) + (assert (= x 41))) (defn test-augassign-div [] "NATIVE: test augassign div" - (let [x 42] - (/= x 2) - (assert (= x 21)))) + (setv x 42) + (/= x 2) + (assert (= x 21))) (defn test-augassign-floordiv [] "NATIVE: test augassign floordiv" - (let [x 42] - (//= x 2) - (assert (= x 21)))) + (setv x 42) + (//= x 2) + (assert (= x 21))) (defn test-augassign-mod [] "NATIVE: test augassign mod" - (let [x 42] - (%= x 2) - (assert (= x 0)))) + (setv x 42) + (%= x 2) + (assert (= x 0))) (defn test-augassign-pow [] "NATIVE: test augassign pow" - (let [x 2] - (**= x 3) - (assert (= x 8)))) + (setv x 2) + (**= x 3) + (assert (= x 8))) (defn test-augassign-lshift [] "NATIVE: test augassign lshift" - (let [x 2] - (<<= x 2) - (assert (= x 8)))) + (setv x 2) + (<<= x 2) + (assert (= x 8))) (defn test-augassign-rshift [] "NATIVE: test augassign rshift" - (let [x 8] - (>>= x 1) - (assert (= x 4)))) + (setv x 8) + (>>= x 1) + (assert (= x 4))) (defn test-augassign-bitand [] "NATIVE: test augassign bitand" - (let [x 8] - (&= x 1) - (assert (= x 0)))) + (setv x 8) + (&= x 1) + (assert (= x 0))) (defn test-augassign-bitor [] "NATIVE: test augassign bitand" - (let [x 0] - (|= x 2) - (assert (= x 2)))) + (setv x 0) + (|= x 2) + (assert (= x 2))) (defn test-augassign-bitxor [] "NATIVE: test augassign bitand" - (let [x 1] - (^= x 1) - (assert (= x 0)))) + (setv x 1) + (^= x 1) + (assert (= x 0))) (defn overflow-int-to-long [] "NATIVE: test if int does not raise an overflow exception" @@ -159,19 +159,19 @@ (defclass HyTestMatrix [list] [--matmul-- (fn [self other] - (let [n (len self) + (setv n (len self) m (len (. other [0])) - result []] - (for [i (range m)] - (let [result-row []] - (for [j (range n)] - (let [dot-product 0] - (for [k (range (len (. self [0])))] - (+= dot-product (* (. self [i] [k]) - (. other [k] [j])))) - (.append result-row dot-product))) - (.append result result-row))) - result))]) + result []) + (for [i (range m)] + (setv result-row []) + (for [j (range n)] + (setv dot-product 0) + (for [k (range (len (. self [0])))] + (+= dot-product (* (. self [i] [k]) + (. other [k] [j])))) + (.append result-row dot-product)) + (.append result result-row)) + result)]) (def first-test-matrix (HyTestMatrix [[1 2 3] [4 5 6] @@ -191,15 +191,16 @@ (assert (= (@ first-test-matrix second-test-matrix) product-of-test-matrices)) ;; Python <= 3.4 - (let [matmul-attempt (try (@ first-test-matrix second-test-matrix) - (except [e [Exception]] e))] + (do + (setv matmul-attempt (try (@ first-test-matrix second-test-matrix) + (except [e [Exception]] e))) (assert (isinstance matmul-attempt NameError))))) (defn test-augassign-matmul [] "NATIVE: test augmented-assignment matrix multiplication" - (let [matrix first-test-matrix + (setv matrix first-test-matrix matmul-attempt (try (@= matrix second-test-matrix) - (except [e [Exception]] e))] - (if PY35 - (assert (= product-of-test-matrices matrix)) - (assert (isinstance matmul-attempt NameError))))) + (except [e [Exception]] e))) + (if PY35 + (assert (= product-of-test-matrices matrix)) + (assert (isinstance matmul-attempt NameError)))) diff --git a/tests/native_tests/native_macros.hy b/tests/native_tests/native_macros.hy index 2d0b19e..6d50899 100644 --- a/tests/native_tests/native_macros.hy +++ b/tests/native_tests/native_macros.hy @@ -132,11 +132,12 @@ (import [astor.codegen [to_source]]) (import [hy.importer [import_buffer_to_ast]]) (setv macro1 "(defmacro nif [expr pos zero neg] - (let [g (gensym)] - `(let [~g ~expr] - (cond [(pos? ~g) ~pos] - [(zero? ~g) ~zero] - [(neg? ~g) ~neg])))) + (setv g (gensym)) + `(do + (setv ~g ~expr) + (cond [(pos? ~g) ~pos] + [(zero? ~g) ~zero] + [(neg? ~g) ~neg]))) (print (nif (inc -1) 1 0 -1)) ") @@ -158,7 +159,8 @@ (import [hy.importer [import_buffer_to_ast]]) (setv macro1 "(defmacro nif [expr pos zero neg] (with-gensyms [a] - `(let [~a ~expr] + `(do + (setv ~a ~expr) (cond [(pos? ~a) ~pos] [(zero? ~a) ~zero] [(neg? ~a) ~neg])))) @@ -180,7 +182,8 @@ (import [astor.codegen [to_source]]) (import [hy.importer [import_buffer_to_ast]]) (setv macro1 "(defmacro/g! nif [expr pos zero neg] - `(let [~g!res ~expr] + `(do + (setv ~g!res ~expr) (cond [(pos? ~g!res) ~pos] [(zero? ~g!res) ~zero] [(neg? ~g!res) ~neg]))) @@ -208,7 +211,8 @@ (import [astor.codegen [to_source]]) (import [hy.importer [import_buffer_to_ast]]) (setv macro1 "(defmacro! nif [expr pos zero neg] - `(let [~g!res ~expr] + `(do + (setv ~g!res ~expr) (cond [(pos? ~g!res) ~pos] [(zero? ~g!res) ~zero] [(neg? ~g!res) ~neg]))) diff --git a/tests/native_tests/py3_only_tests.hy b/tests/native_tests/py3_only_tests.hy index 4889440..30044b1 100644 --- a/tests/native_tests/py3_only_tests.hy +++ b/tests/native_tests/py3_only_tests.hy @@ -15,24 +15,23 @@ (defn test-kwonly [] "NATIVE: test keyword-only arguments" ;; keyword-only with default works - (let [kwonly-foo-default-false (fn [&kwonly [foo False]] foo)] - (assert (= (apply kwonly-foo-default-false) False)) - (assert (= (apply kwonly-foo-default-false [] {"foo" True}) True))) + (defn kwonly-foo-default-false [&kwonly [foo False]] foo) + (assert (= (apply kwonly-foo-default-false) False)) + (assert (= (apply kwonly-foo-default-false [] {"foo" True}) True)) ;; keyword-only without default ... - (let [kwonly-foo-no-default (fn [&kwonly foo] foo) - attempt-to-omit-default (try - (kwonly-foo-no-default) - (except [e [Exception]] e))] - ;; works - (assert (= (apply kwonly-foo-no-default [] {"foo" "quux"}) "quux")) - ;; raises TypeError with appropriate message if not supplied - (assert (isinstance attempt-to-omit-default TypeError)) - (assert (in "missing 1 required keyword-only argument: 'foo'" - (. attempt-to-omit-default args [0])))) + (defn kwonly-foo-no-default [&kwonly foo] foo) + (setv attempt-to-omit-default (try + (kwonly-foo-no-default) + (except [e [Exception]] e))) + ;; works + (assert (= (apply kwonly-foo-no-default [] {"foo" "quux"}) "quux")) + ;; raises TypeError with appropriate message if not supplied + (assert (isinstance attempt-to-omit-default TypeError)) + (assert (in "missing 1 required keyword-only argument: 'foo'" + (. attempt-to-omit-default args [0]))) ;; keyword-only with other arg types works - (let [function-of-various-args - (fn [a b &rest args &kwonly foo &kwargs kwargs] - (, a b args foo kwargs))] - (assert (= (apply function-of-various-args - [1 2 3 4] {"foo" 5 "bar" 6 "quux" 7}) - (, 1 2 (, 3 4) 5 {"bar" 6 "quux" 7}))))) + (defn function-of-various-args [a b &rest args &kwonly foo &kwargs kwargs] + (, a b args foo kwargs)) + (assert (= (apply function-of-various-args + [1 2 3 4] {"foo" 5 "bar" 6 "quux" 7}) + (, 1 2 (, 3 4) 5 {"bar" 6 "quux" 7})))) diff --git a/tests/native_tests/shadow.hy b/tests/native_tests/shadow.hy index 6251b2e..72ac0b9 100644 --- a/tests/native_tests/shadow.hy +++ b/tests/native_tests/shadow.hy @@ -1,51 +1,51 @@ (defn test-shadow-addition [] "NATIVE: test shadow addition" - (let [x +] - (assert (try - (x) - (except [TypeError] True) - (else (raise AssertionError)))) - (assert (= (x 1 2 3 4) 10)) - (assert (= (x 1 2 3 4 5) 15)) - ; with strings - (assert (= (x "a" "b" "c") - "abc")) - ; with lists - (assert (= (x ["a"] ["b"] ["c"]) - ["a" "b" "c"])))) + (setv x +) + (assert (try + (x) + (except [TypeError] True) + (else (raise AssertionError)))) + (assert (= (x 1 2 3 4) 10)) + (assert (= (x 1 2 3 4 5) 15)) + ; with strings + (assert (= (x "a" "b" "c") + "abc")) + ; with lists + (assert (= (x ["a"] ["b"] ["c"]) + ["a" "b" "c"]))) (defn test-shadow-subtraction [] "NATIVE: test shadow subtraction" - (let [x -] - (assert (try - (x) - (except [TypeError] True) - (else (raise AssertionError)))) - (assert (= (x 1) -1)) - (assert (= (x 2 1) 1)) - (assert (= (x 2 1 1) 0)))) + (setv x -) + (assert (try + (x) + (except [TypeError] True) + (else (raise AssertionError)))) + (assert (= (x 1) -1)) + (assert (= (x 2 1) 1)) + (assert (= (x 2 1 1) 0))) (defn test-shadow-multiplication [] "NATIVE: test shadow multiplication" - (let [x *] - (assert (= (x) 1)) - (assert (= (x 3) 3)) - (assert (= (x 3 3) 9)))) + (setv x *) + (assert (= (x) 1)) + (assert (= (x 3) 3)) + (assert (= (x 3 3) 9))) (defn test-shadow-division [] "NATIVE: test shadow division" - (let [x /] - (assert (try - (x) - (except [TypeError] True) - (else (raise AssertionError)))) - (assert (= (x 1) 1)) - (assert (= (x 8 2) 4)) - (assert (= (x 8 2 2) 2)) - (assert (= (x 8 2 2 2) 1)))) + (setv x /) + (assert (try + (x) + (except [TypeError] True) + (else (raise AssertionError)))) + (assert (= (x 1) 1)) + (assert (= (x 8 2) 4)) + (assert (= (x 8 2 2) 2)) + (assert (= (x 8 2 2 2) 1))) (defn test-shadow-compare [] @@ -70,24 +70,24 @@ [2 2]]] (assert (= (apply x args) (not (apply y args)))))) - (let [s-lt < + (setv s-lt < s-gt > s-le <= s-ge >= s-eq = - s-ne !=] - (assert (apply s-lt [1 2 3])) - (assert (not (apply s-lt [3 2 1]))) - (assert (apply s-gt [3 2 1])) - (assert (not (apply s-gt [1 2 3]))) - (assert (apply s-le [1 1 2 2 3 3])) - (assert (not (apply s-le [1 1 2 2 1 1]))) - (assert (apply s-ge [3 3 2 2 1 1])) - (assert (not (apply s-ge [3 3 2 2 3 3]))) - (assert (apply s-eq [1 1 1 1 1])) - (assert (not (apply s-eq [1 1 2 1 1]))) - (assert (apply s-ne [1 2 3 4 5])) - (assert (not (apply s-ne [1 1 2 3 4])))) + s-ne !=) + (assert (apply s-lt [1 2 3])) + (assert (not (apply s-lt [3 2 1]))) + (assert (apply s-gt [3 2 1])) + (assert (not (apply s-gt [1 2 3]))) + (assert (apply s-le [1 1 2 2 3 3])) + (assert (not (apply s-le [1 1 2 2 1 1]))) + (assert (apply s-ge [3 3 2 2 1 1])) + (assert (not (apply s-ge [3 3 2 2 3 3]))) + (assert (apply s-eq [1 1 1 1 1])) + (assert (not (apply s-eq [1 1 2 1 1]))) + (assert (apply s-ne [1 2 3 4 5])) + (assert (not (apply s-ne [1 1 2 3 4]))) ; Make sure chained comparisons use `and`, not `&`. ; https://github.com/hylang/hy/issues/1191 From b1df5d14285fb0643b22dddc245102b25434bfd1 Mon Sep 17 00:00:00 2001 From: Kodi Arfer Date: Sat, 4 Feb 2017 09:18:22 -0800 Subject: [PATCH 3/8] Remove extra uses of `let` in native_tests.language Tests of `let` itself remain. --- tests/native_tests/language.hy | 218 ++++++++++++++++----------------- 1 file changed, 109 insertions(+), 109 deletions(-) diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index 3d5124c..550db13 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -449,51 +449,51 @@ (try (do) (except [IOError]) (except)) ;; Test correct (raise) - (let [passed False] - (try - (try - (raise IndexError) - (except [IndexError] (raise))) - (except [IndexError] - (setv passed True))) - (assert passed)) + (setv passed False) + (try + (try + (raise IndexError) + (except [IndexError] (raise))) + (except [IndexError] + (setv passed True))) + (assert passed) ;; Test incorrect (raise) - (let [passed False] - (try - (raise) - ;; Python 2 raises TypeError - ;; Python 3 raises RuntimeError - (except [[TypeError RuntimeError]] - (setv passed True))) - (assert passed)) + (setv passed False) + (try + (raise) + ;; Python 2 raises TypeError + ;; Python 3 raises RuntimeError + (except [[TypeError RuntimeError]] + (setv passed True))) + (assert passed) ;; Test (finally) - (let [passed False] - (try - (do) - (finally (setv passed True))) - (assert passed)) + (setv passed False) + (try + (do) + (finally (setv passed True))) + (assert passed) ;; Test (finally) + (raise) - (let [passed False] - (try - (raise Exception) - (except) - (finally (setv passed True))) - (assert passed)) + (setv passed False) + (try + (raise Exception) + (except) + (finally (setv passed True))) + (assert passed) ;; Test (finally) + (raise) + (else) - (let [passed False - not-elsed True] - (try - (raise Exception) - (except) - (else (setv not-elsed False)) - (finally (setv passed True))) - (assert passed) - (assert not-elsed)) + (setv passed False + not-elsed True) + (try + (raise Exception) + (except) + (else (setv not-elsed False)) + (finally (setv passed True))) + (assert passed) + (assert not-elsed) (try (raise (KeyError)) @@ -553,37 +553,37 @@ (setv foobar42ofthebaz 42) (assert (= foobar42ofthebaz 42)))) - (let [passed False] - (try - (try (do) (except) (else (bla))) - (except [NameError] (setv passed True))) - (assert passed)) + (setv passed False) + (try + (try (do) (except) (else (bla))) + (except [NameError] (setv passed True))) + (assert passed) - (let [x 0] - (try - (raise IOError) - (except [IOError] - (setv x 45)) - (else (setv x 44))) - (assert (= x 45))) + (setv x 0) + (try + (raise IOError) + (except [IOError] + (setv x 45)) + (else (setv x 44))) + (assert (= x 45)) - (let [x 0] - (try - (raise KeyError) - (except [] - (setv x 45)) - (else (setv x 44))) - (assert (= x 45))) + (setv x 0) + (try + (raise KeyError) + (except [] + (setv x 45)) + (else (setv x 44))) + (assert (= x 45)) - (let [x 0] - (try - (try - (raise KeyError) - (except [IOError] - (setv x 45)) - (else (setv x 44))) - (except)) - (assert (= x 0)))) + (setv x 0) + (try + (try + (raise KeyError) + (except [IOError] + (setv x 45)) + (else (setv x 44))) + (except)) + (assert (= x 0))) (defn test-earmuffs [] "NATIVE: Test earmuffs" @@ -677,9 +677,9 @@ (defn test-yield-in-try [] "NATIVE: test yield in try" (defn gen [] - (let [x 1] + (setv x 1) (try (yield x) - (finally (print x))))) + (finally (print x)))) (setv output (list (gen))) (assert (= [1] output))) @@ -747,17 +747,17 @@ (defn test-for-else [] "NATIVE: test for else" - (let [x 0] - (for* [a [1 2]] - (setv x (+ x a)) - (else (setv x (+ x 50)))) - (assert (= x 53))) + (setv x 0) + (for* [a [1 2]] + (setv x (+ x a)) + (else (setv x (+ x 50)))) + (assert (= x 53)) - (let [x 0] - (for* [a [1 2]] - (setv x (+ x a)) - (else)) - (assert (= x 3)))) + (setv x 0) + (for* [a [1 2]] + (setv x (+ x a)) + (else)) + (assert (= x 3))) (defn test-list-comprehensions [] @@ -921,35 +921,36 @@ (defn test-symbol-utf-8 [] "NATIVE: test symbol encoded" - (let [♥ "love" - ⚘ "flower"] - (assert (= (+ ⚘ ♥) "flowerlove")))) + (setv ♥ "love" + ⚘ "flower") + (assert (= (+ ⚘ ♥) "flowerlove"))) (defn test-symbol-dash [] "NATIVE: test symbol encoded" - (let [♥-♥ "doublelove" - -_- "what?"] - (assert (= ♥-♥ "doublelove")) - (assert (= -_- "what?")))) + (setv ♥-♥ "doublelove" + -_- "what?") + (assert (= ♥-♥ "doublelove")) + (assert (= -_- "what?"))) (defn test-symbol-question-mark [] "NATIVE: test foo? -> is_foo behavior" - (let [foo? "nachos"] - (assert (= is_foo "nachos")))) + (setv foo? "nachos") + (assert (= is_foo "nachos"))) (defn test-and [] "NATIVE: test the and function" - (let [and123 (and 1 2 3) + + (setv and123 (and 1 2 3) and-false (and 1 False 3) and-true (and) - and-single (and 1)] - (assert (= and123 3)) - (assert (= and-false False)) - (assert (= and-true True)) - (assert (= and-single 1))) + and-single (and 1)) + (assert (= and123 3)) + (assert (= and-false False)) + (assert (= and-true True)) + (assert (= and-single 1)) ; short circuiting (setv a 1) (and 0 (setv a 2)) @@ -980,16 +981,16 @@ (defn test-or [] "NATIVE: test the or function" - (let [or-all-true (or 1 2 3 True "string") + (setv or-all-true (or 1 2 3 True "string") or-some-true (or False "hello") or-none-true (or False False) or-false (or) - or-single (or 1)] - (assert (= or-all-true 1)) - (assert (= or-some-true "hello")) - (assert (= or-none-true False)) - (assert (= or-false None)) - (assert (= or-single 1))) + or-single (or 1)) + (assert (= or-all-true 1)) + (assert (= or-some-true "hello")) + (assert (= or-none-true False)) + (assert (= or-false None)) + (assert (= or-single 1)) ; short circuiting (setv a 1) (or 1 (setv a 2)) @@ -1107,17 +1108,16 @@ (defn test-eval-globals [] "NATIVE: test eval with explicit global dict" (assert (= 'bar (eval (quote foo) {'foo 'bar}))) - (assert (= 1 (let [d {}] (eval '(setv x 1) d) (eval (quote x) d)))) - (let [d1 {} - d2 {}] - (eval '(setv x 1) d1) - (try - (do - ; this should fail with a name error - (eval (quote x) d2) - (assert False "We shouldn't have arrived here")) - (except [e Exception] - (assert (isinstance e NameError)))))) + (assert (= 1 (do (setv d {}) (eval '(setv x 1) d) (eval (quote x) d)))) + (setv d1 {} d2 {}) + (eval '(setv x 1) d1) + (try + (do + ; this should fail with a name error + (eval (quote x) d2) + (assert False "We shouldn't have arrived here")) + (except [e Exception] + (assert (isinstance e NameError))))) (defn test-eval-failure [] "NATIVE: test eval failure modes" From 31f3a55a2687a33763b55da52c94de89e1a28a07 Mon Sep 17 00:00:00 2001 From: Kodi Arfer Date: Mon, 13 Feb 2017 09:12:13 -0800 Subject: [PATCH 4/8] Remove tests of `let` --- tests/compilers/test_ast.py | 16 --------- tests/native_tests/language.hy | 65 ++++------------------------------ 2 files changed, 6 insertions(+), 75 deletions(-) diff --git a/tests/compilers/test_ast.py b/tests/compilers/test_ast.py index 9a1a05e..4719ef8 100644 --- a/tests/compilers/test_ast.py +++ b/tests/compilers/test_ast.py @@ -333,22 +333,6 @@ def test_ast_invalid_for(): cant_compile("(for* [a 1] (else 1 2))") -def test_ast_valid_let(): - "Make sure AST can compile valid let" - can_compile("(let [a b])") - can_compile("(let [a 1])") - can_compile("(let [a 1 b None])") - - -def test_ast_invalid_let(): - "Make sure AST can't compile invalid let" - cant_compile("(let 1)") - cant_compile("(let [1])") - cant_compile("(let [a 1 2])") - cant_compile("(let [a])") - cant_compile("(let [1])") - - def test_ast_expression_basics(): """ Ensure basic AST expression conversion works. """ code = can_compile("(foo bar)").body[0] diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index 550db13..1ed7260 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -864,37 +864,6 @@ (assert (= (fn-test) None))) -(defn test-let [] - "NATIVE: test let works rightish" - ;; TODO: test sad paths for let - (assert (= (let [x 1 y 2 z 3] (+ x y z)) 6)) - (assert (= (let [x 1 a None y 2 b None] (if a 1 2)) 2)) - (assert (= (let [x None] x) None)) - (assert (= (let [x "x not bound"] (setv x "x bound by setv") x) - "x bound by setv")) - (assert (= (let [x "let nests scope correctly"] - (let [y None] x)) - "let nests scope correctly")) - (assert (= (let [x 999999] - (let [x "x being rebound"] x)) - "x being rebound")) - (assert (= (let [x "x not being rebound"] - (let [x 2] None) - x) - "x not being rebound")) - (assert (= (let [x (set [3 2 1 3 2]) y x z y] z) (set [1 2 3]))) - (import math) - (let [cos math.cos - foo-cos (fn [x] (cos x))] - (assert (= (cos math.pi) -1.0)) - (assert (= (foo-cos (- math.pi)) -1.0)) - (let [cos (fn [_] "cos has been locally rebound")] - (assert (= (cos cos) "cos has been locally rebound")) - (assert (= (-> math.pi (/ 3) foo-cos (round 2)) 0.5))) - (setv cos (fn [_] "cos has been rebound by setv")) - (assert (= (foo-cos foo-cos) "cos has been rebound by setv")))) - - (defn test-if-mangler [] "NATIVE: test that we return ifs" (assert (= True (if True True True)))) @@ -905,20 +874,6 @@ (assert (= ((fn [] (-> 2 (+ 1 1) (* 1 2)))) 8))) -(defn test-let-scope [] - "NATIVE: test let works rightish" - (setv y 123) - (assert (= (let [x 1 - y 2 - z 3] - (+ x y z)) - 6)) - (try - (assert (= x 42)) ; This ain't true - (except [e [NameError]] (assert e))) - (assert (= y 123))) - - (defn test-symbol-utf-8 [] "NATIVE: test symbol encoded" (setv ♥ "love" @@ -1040,16 +995,12 @@ (defn test-if-return-branching [] "NATIVE: test the if return branching" - ; thanks, algernon - (assert (= 1 (let [x 1 - y 2] - (if True - 2) - 1))) - (assert (= 1 (let [x 1 y 2] - (do) - (do) - ((fn [] 1)))))) + ; thanks, kirbyfan64 + (defn f [] + (if True (setv x 1) 2) + 1) + + (assert (= 1 (f)))) (defn test-keyword [] @@ -1187,10 +1138,6 @@ (assert False)) (except [NameError]))) -(defn test-if-let-mixing [] - "NATIVE: test that we can now mix if and let" - (assert (= 0 (if True (let [x 0] x) 42)))) - (defn test-if-in-if [] "NATIVE: test that we can use if in if" (assert (= 42 From 2a44928eb75d8d91d59b3a65327796062953052c Mon Sep 17 00:00:00 2001 From: Kodi Arfer Date: Sat, 4 Feb 2017 09:54:39 -0800 Subject: [PATCH 5/8] Remove `let` Yes, bizarrely, this does require editing the implementation of `defn` a little. Without the import, HyList isn't in scope. Defining `let` made it visible due to black magic regarding automatic import. --- NEWS | 2 ++ hy/core/bootstrap.hy | 16 +++------------- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/NEWS b/NEWS index 0f4b5f6..2414f89 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,8 @@ Changes from 0.12.1 [ Language Changes ] + * `let` has been removed. Python's scoping rules do not make a proper + implementation of it possible. Use `setv` instead. * xor: If exactly one argument is true, return it [ Bug Fixes ] diff --git a/hy/core/bootstrap.hy b/hy/core/bootstrap.hy index 8d8a3f8..4b07e91 100644 --- a/hy/core/bootstrap.hy +++ b/hy/core/bootstrap.hy @@ -41,23 +41,13 @@ (defmacro defn [name lambda-list &rest body] "define a function `name` with signature `lambda-list` and body `body`" - (if (not (= (type name) HySymbol)) + (import hy) + (if (not (= (type name) hy.HySymbol)) (macro-error name "defn takes a name as first argument")) - (if (not (isinstance lambda-list HyList)) + (if (not (isinstance lambda-list hy.HyList)) (macro-error name "defn takes a parameter list as second argument")) `(setv ~name (fn ~lambda-list ~@body))) -(defmacro let [variables &rest body] - "Execute `body` in the lexical context of `variables`" - (if (not (isinstance variables HyList)) - (macro-error variables "let lexical context must be a list")) - (if (= (len variables) 0) - `((fn [] - ~@body)) - `((fn [] - (setv ~@variables) - ~@body)))) - (defmacro if-python2 [python2-form python3-form] "If running on python2, execute python2-form, else, execute python3-form" (import sys) From 3ec919278d72dde6c803b8c6788eff0ac0076c16 Mon Sep 17 00:00:00 2001 From: Kodi Arfer Date: Thu, 9 Feb 2017 11:33:09 -0800 Subject: [PATCH 6/8] Remove `let` from documentation --- docs/language/api.rst | 93 ++++++++++++------------------------- docs/language/core.rst | 7 ++- docs/language/internals.rst | 36 +++++++------- docs/style-guide.rst | 9 ---- docs/tutorial.rst | 8 ++-- 5 files changed, 56 insertions(+), 97 deletions(-) diff --git a/docs/language/api.rst b/docs/language/api.rst index ee91be3..de14a7e 100644 --- a/docs/language/api.rst +++ b/docs/language/api.rst @@ -286,17 +286,20 @@ Examples of usage: .. code-block:: clj - =>(let [collection {}] + =>(do + ... (setv collection {}) ... (assoc collection "Dog" "Bark") ... (print collection)) {u'Dog': u'Bark'} - =>(let [collection {}] + =>(do + ... (setv collection {}) ... (assoc collection "Dog" "Bark" "Cat" "Meow") ... (print collection)) {u'Cat': u'Meow', u'Dog': u'Bark'} - =>(let [collection [1 2 3 4]] + =>(do + ... (setv collection [1 2 3 4]) ... (assoc collection 2 None) ... (print collection)) [1, 2, None, 4] @@ -555,9 +558,9 @@ Parameters may have the following keywords in front of them: .. code-block:: clj => (defn zig-zag-sum [&rest numbers] - (let [odd-numbers (list-comp x [x numbers] (odd? x)) - even-numbers (list-comp x [x numbers] (even? x))] - (- (sum odd-numbers) (sum even-numbers)))) + (setv odd-numbers (list-comp x [x numbers] (odd? x)) + even-numbers (list-comp x [x numbers] (even? x))) + (- (sum odd-numbers) (sum even-numbers))) => (zig-zag-sum) 0 @@ -578,10 +581,10 @@ Parameters may have the following keywords in front of them: .. code-block:: clj => (defn compare [a b &kwonly keyfn [reverse false]] - ... (let [result (keyfn a b)] - ... (if (not reverse) - ... result - ... (- result)))) + ... (setv result (keyfn a b)) + ... (if (not reverse) + ... result + ... (- result))) => (apply compare ["lisp" "python"] ... {"keyfn" (fn [x y] ... (reduce - (map (fn [s] (ord (first s))) [x y])))}) @@ -932,8 +935,9 @@ list. Example usage: .. code-block:: clj - => (let [animals {"dog" "bark" "cat" "meow"} - ... numbers ["zero" "one" "two" "three"]] + => (do + ... (setv animals {"dog" "bark" "cat" "meow"} + ... numbers ["zero" "one" "two" "three"]) ... (print (get animals "dog")) ... (print (get numbers 2))) bark @@ -1148,36 +1152,6 @@ last 6 -let ---- - -``let`` is used to create lexically scoped variables. They are created at the -beginning of the ``let`` form and cease to exist after the form. The following -example showcases this behaviour: - -.. code-block:: clj - - => (let [x 5] (print x) - ... (let [x 6] (print x)) - ... (print x)) - 5 - 6 - 5 - -The ``let`` macro takes two parameters: a vector defining *variables* -and the *body* which gets executed. *variables* is a vector of -variable and value pairs. - -Note that the variable assignments are executed one by one, from left to right. -The following example takes advantage of this: - -.. code-block:: clj - - => (let [x 5 - y (+ x 1)] (print x y)) - 5 6 - - list-comp --------- @@ -1209,30 +1183,20 @@ nonlocal ``nonlocal`` can be used to mark a symbol as not local to the current scope. The parameters are the names of symbols to mark as nonlocal. This is necessary -to modify variables through nested ``let`` or ``fn`` scopes: +to modify variables through nested ``fn`` scopes: .. code-block:: clj - (let [x 0] - (for [y (range 10)] - (let [z (inc y)] - (nonlocal x) ; allow the setv to "jump scope" to resolve x - (setv x (+ x y)))) - x) - (defn some-function [] - (let [x 0] - (register-some-callback - (fn [stuff] - (nonlocal x) - (setv x stuff))))) + (setv x 0) + (register-some-callback + (fn [stuff] + (nonlocal x) + (setv x stuff)))) -In the first example, without the call to ``(nonlocal x)``, this code would -result in an UnboundLocalError being raised during the call to ``setv``. - -In the second example, without the call to ``(nonlocal x)``, the inner function -would redefine ``x`` to ``stuff`` inside its local scope instead of overwriting -the ``x`` in the outer function +Without the call to ``(nonlocal x)``, the inner function would redefine ``x`` to +``stuff`` inside its local scope instead of overwriting the ``x`` in the outer +function. See `PEP3104 `_ for further information. @@ -1698,9 +1662,10 @@ expands to: .. code-block:: hy - (let [a (gensym) - b (gensym) - c (gensym)] + (do + (setv a (gensym) + b (gensym) + c (gensym)) ...) .. seealso:: diff --git a/docs/language/core.rst b/docs/language/core.rst index 2272911..43c9ad6 100644 --- a/docs/language/core.rst +++ b/docs/language/core.rst @@ -1203,10 +1203,9 @@ if *from-file* ends before a complete expression can be parsed. => (with [f (open "example.hy")] ... (try ... (while True - ... (let [exp (read f)] - ... (do - ... (print "OHY" exp) - ... (eval exp)))) + ... (setv exp (read f)) + ... (print "OHY" exp) + ... (eval exp)) ... (except [e EOFError] ... (print "EOF!")))) OHY ('print' 'hello') diff --git a/docs/language/internals.rst b/docs/language/internals.rst index 3960c07..0a1f948 100644 --- a/docs/language/internals.rst +++ b/docs/language/internals.rst @@ -381,7 +381,8 @@ A first pass might be something like: .. code-block:: hy (defmacro nif [expr pos-form zero-form neg-form] - `(let [obscure-name ~expr] + `(do + (setv obscure-name ~expr) (cond [(pos? obscure-name) ~pos-form] [(zero? obscure-name) ~zero-form] [(neg? obscure-name) ~neg-form]))) @@ -396,15 +397,16 @@ such an occasion. A much better version of ``nif`` would be: .. code-block:: hy (defmacro nif [expr pos-form zero-form neg-form] - (let [g (gensym)] - `(let [~g ~expr] - (cond [(pos? ~g) ~pos-form] - [(zero? ~g) ~zero-form] - [(neg? ~g) ~neg-form])))) + (setv g (gensym)) + `(do + (setv ~g ~expr) + (cond [(pos? ~g) ~pos-form] + [(zero? ~g) ~zero-form] + [(neg? ~g) ~neg-form]))) This is an easy case, since there is only one symbol. But if there is a need for several gensym's there is a second macro :ref:`with-gensyms` that -basically expands to a series of ``let`` statements: +basically expands to a ``setv`` form: .. code-block:: hy @@ -415,9 +417,10 @@ expands to: .. code-block:: hy - (let [a (gensym) - b (gensym) - c (gensym)] + (do + (setv a (gensym) + b (gensym) + c (gensym)) ...) so our re-written ``nif`` would look like: @@ -426,10 +429,10 @@ so our re-written ``nif`` would look like: (defmacro nif [expr pos-form zero-form neg-form] (with-gensyms [g] - `(let [~g ~expr] - (cond [(pos? ~g) ~pos-form] - [(zero? ~g) ~zero-form] - [(neg? ~g) ~neg-form])))) + `(setv [~g ~expr]) + `(cond [(pos? ~g) ~pos-form] + [(zero? ~g) ~zero-form] + [(neg? ~g) ~neg-form]))) Finally, though we can make a new macro that does all this for us. :ref:`defmacro/g!` will take all symbols that begin with ``g!`` and automatically call ``gensym`` with the @@ -440,10 +443,11 @@ Our final version of ``nif``, built with ``defmacro/g!`` becomes: .. code-block:: hy (defmacro/g! nif [expr pos-form zero-form neg-form] - `(let [~g!res ~expr] + `(do + (setv ~g!res ~expr) (cond [(pos? ~g!res) ~pos-form] [(zero? ~g!res) ~zero-form] - [(neg? ~g!res) ~neg-form])))) + [(neg? ~g!res) ~neg-form]))) diff --git a/docs/style-guide.rst b/docs/style-guide.rst index 0ed87a9..0f8aa40 100644 --- a/docs/style-guide.rst +++ b/docs/style-guide.rst @@ -101,15 +101,6 @@ Layout & Indentation ) ; GAH, BURN IT WITH FIRE -+ Vertically align ``let`` blocks. - - .. code-block:: clj - - (let [foo (bar) - qux (baz)] - (foo qux)) - - + Inline comments shall be two spaces from the end of the code; they must always have a space between the comment character and the start of the comment. Also, try to not comment the obvious. diff --git a/docs/tutorial.rst b/docs/tutorial.rst index 4bbbb51..a8fe5b4 100644 --- a/docs/tutorial.rst +++ b/docs/tutorial.rst @@ -539,8 +539,8 @@ We can also manipulate code with macros: .. code-block:: clj => (defmacro rev [code] - ... (let [op (last code) params (list (butlast code))] - ... `(~op ~@params))) + ... (setv op (last code) params (list (butlast code))) + ... `(~op ~@params)) => (rev (1 2 3 +)) 6 @@ -559,8 +559,8 @@ characters that soon): .. code-block:: clj => (defreader ↻ [code] - ... (let [op (last code) params (list (butlast code))] - ... `(~op ~@params))) + ... (setv op (last code) params (list (butlast code))) + ... `(~op ~@params)) => #↻(1 2 3 +) 6 From 9f4b630e1438ccfea5a24f7182a15ea1d8a51659 Mon Sep 17 00:00:00 2001 From: Kodi Arfer Date: Sat, 4 Feb 2017 11:20:01 -0800 Subject: [PATCH 7/8] Fix Python 2 issue in take-nth It was trying to `return` a value in a generator, which Python 2 forbids. --- hy/core/language.hy | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/hy/core/language.hy b/hy/core/language.hy index 54f24d8..af20799 100644 --- a/hy/core/language.hy +++ b/hy/core/language.hy @@ -419,14 +419,13 @@ (defn take-nth [n coll] "Return every nth member of coll raises ValueError for (not (pos? n))" - (if (pos? n) - (do - (setv citer (iter coll) skip (dec n)) - (for* [val citer] - (yield val) - (for* [_ (range skip)] - (next citer)))) - (raise (ValueError "n must be positive")))) + (if (not (pos? n)) + (raise (ValueError "n must be positive"))) + (setv citer (iter coll) skip (dec n)) + (for* [val citer] + (yield val) + (for* [_ (range skip)] + (next citer)))) (defn zero? [n] "Return true if n is 0" From 23a7363cce2a5561f877eef4eb88c88ec87334d5 Mon Sep 17 00:00:00 2001 From: Kodi Arfer Date: Sat, 4 Feb 2017 12:03:37 -0800 Subject: [PATCH 8/8] Fix a test for Python 2 --- tests/native_tests/language.hy | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index 1ed7260..b5f8d43 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -462,9 +462,9 @@ (setv passed False) (try (raise) - ;; Python 2 raises TypeError + ;; Python 2 raises IndexError here (due to the previous test) ;; Python 3 raises RuntimeError - (except [[TypeError RuntimeError]] + (except [[IndexError RuntimeError]] (setv passed True))) (assert passed)