Change the signature of (for) and (with).

(for) is restored to clojure-like flatness.
 (with) can be used without the nested list if you don't care about the
        name.

   Tests and examples updated.
This commit is contained in:
Paul Tagliamonte 2013-12-31 13:35:31 -05:00
parent 8cabf22749
commit eeef65b505
7 changed files with 56 additions and 36 deletions

2
NEWS
View File

@ -55,8 +55,6 @@ Changes from Hy 0.9.11
[ Syntax Fixes ]
* for changed syntax from (for [] ...) -> (for [[]] ...)
* with changed syntax from (with [] ...) -> (with [[]] ...)
* get allows multiple arguments

View File

@ -205,11 +205,12 @@ however is called only for every other value in the list.
;; assuming that (side-effect1) and (side-effect2) are functions and
;; collection is a list of numerical values
(for (x collection) (do
(side-effect1 x)
(if (% x 2)
(continue))
(side-effect2 x)))
(for [x collection]
(do
(side-effect1 x)
(if (% x 2)
(continue))
(side-effect2 x)))
do / progn
@ -489,10 +490,10 @@ collection and calls side-effect to each element in the collection:
.. code-block:: clj
;; assuming that (side-effect) is a function that takes a single parameter
(for [[element collection]] (side-effect element))
(for [element collection] (side-effect element))
;; for can have an optional else block
(for [[element collection]] (side-effect element)
(for [element collection] (side-effect element)
(else (side-effect-2)))
The optional `else` block is executed only if the `for` loop terminates
@ -500,14 +501,14 @@ normally. If the execution is halted with `break`, the `else` does not execute.
.. code-block:: clj
=> (for [[element [1 2 3]]] (if (< element 3)
=> (for [element [1 2 3]] (if (< element 3)
... (print element)
... (break))
... (else (print "loop finished")))
1
2
=> (for [[element [1 2 3]]] (if (< element 4)
=> (for [element [1 2 3]] (if (< element 4)
... (print element)
... (break))
... (else (print "loop finished")))
@ -680,7 +681,7 @@ function is defined and passed to another function for filtering output.
... {:name "Dave" :age 5}])
=> (defn display-people [people filter]
... (for [[person people]] (if (filter person) (print (:name person)))))
... (for [person people] (if (filter person) (print (:name person)))))
=> (display-people people (fn [person] (< (:age person) 25)))
Alice

View File

@ -7,5 +7,5 @@
(with-as (ThreadPoolExecutor 10) executor
(setv jobs (list-comp (.submit executor task-to-do) (x (range 0 10))))
(for (future (as-completed jobs))
(for [future (as-completed jobs)]
(.result future)))

View File

@ -31,14 +31,14 @@
(defmacro ap-each [lst &rest body]
"Evaluate the body form for each element in the list."
`(for [[it ~lst]] ~@body))
`(for [it ~lst] ~@body))
(defmacro ap-each-while [lst form &rest body]
"Evalutate the body form for each element in the list while the
predicate form evaluates to True."
`(let [[p (lambda [it] ~form)]]
(for [[it ~lst]]
(for [it ~lst]
(if (p it)
~@body
(break)))))
@ -47,7 +47,7 @@
(defmacro ap-map [form lst]
"Yield elements evaluated in the form for each element in the list."
`(let [[f (lambda [it] ~form)]]
(for [[v ~lst]]
(for [v ~lst]
(yield (f v)))))
@ -55,7 +55,7 @@
"Yield elements evaluated for each element in the list when the
predicate function returns True."
`(let [[f (lambda [it] ~rep)]]
(for [[it ~lst]]
(for [it ~lst]
(if (~predfn it)
(yield (f it))
(yield it)))))
@ -64,7 +64,7 @@
(defmacro ap-filter [form lst]
"Yield elements returned when the predicate form evaluates to True."
`(let [[pred (lambda [it] ~form)]]
(for [[val ~lst]]
(for [val ~lst]
(if (pred val)
(yield val)))))

View File

@ -25,16 +25,29 @@
;;; These macros form the hy language
;;; They are automatically required in every module, except inside hy.core
(import [hy.models.list [HyList]]
[hy.models.symbol [HySymbol]])
(defmacro for [args &rest body]
"shorthand for nested for loops:
(for [[x foo] [y bar]] baz) ->
(for [x foo
y bar]
baz) ->
(for* [x foo]
(for* [y bar]
baz))"
(if (odd? (len args))
(macro-error args "`for' requires an even number of args."))
(if (empty? body)
(macro-error None "`for' requires a body to evaluate"))
(if args
`(for* ~(.pop args 0) (for ~args ~@body))
`(for* [~(.pop args 0) ~(.pop args 0)]
(for ~args ~@body))
`(do ~@body)))
@ -44,9 +57,17 @@
(with* [x foo]
(with* [y bar]
baz))"
(if args
`(with* ~(.pop args 0) (with ~args ~@body))
`(do ~@body)))
(if (not (empty? args))
(let [[primary (.pop args 0)]]
(if (isinstance primary HyList)
;;; OK. if we have a list, we can go ahead and unpack that
;;; as the argument to with.
`(with* [~@primary] (with ~args ~@body))
;;; OK, let's just give it away. This may not be something we
;;; can do, but that's really the programmer's problem.
`(with* [~primary] (with ~args ~@body))))
`(do ~@body)))
(defmacro-alias [car first] [thing]

View File

@ -313,7 +313,7 @@ def test_ast_valid_while():
def test_ast_valid_for():
"Make sure AST can compile valid for"
can_compile("(for [[a 2]] (print a))")
can_compile("(for [a 2] (print a))")
def test_ast_invalid_for():
@ -452,14 +452,14 @@ def test_for_compile_error():
assert(False)
try:
can_compile("(fn [] (for [[x]]))")
can_compile("(fn [] (for [x]))")
except HyTypeError as e:
assert(e.message == "`for' requires a body to evaluate")
assert(e.message == "`for' requires an even number of args.")
else:
assert(False)
try:
can_compile("(fn [] (for [[x xx]]))")
can_compile("(fn [] (for [x xx]))")
except HyTypeError as e:
assert(e.message == "`for' requires a body to evaluate")
else:

View File

@ -31,12 +31,12 @@
(defn test-for-loop []
"NATIVE: test for loops?"
(setv count 0)
(for [[x [1 2 3 4 5]]]
(for [x [1 2 3 4 5]]
(setv count (+ count x)))
(assert (= count 15))
(setv count 0)
(for [[x [1 2 3 4 5]]
[y [1 2 3 4 5]]]
(for [x [1 2 3 4 5]
y [1 2 3 4 5]]
(setv count (+ count x y)))
(assert (= count 150)))
@ -404,9 +404,9 @@
(defn test-yield []
"NATIVE: test yielding"
(defn gen [] (for [[x [1 2 3 4]]] (yield x)))
(defn gen [] (for [x [1 2 3 4]] (yield x)))
(setv ret 0)
(for [[y (gen)]] (setv ret (+ ret y)))
(for [y (gen)] (setv ret (+ ret y)))
(assert (= ret 10)))
@ -463,7 +463,7 @@
(defn test-for-doodle []
"NATIVE: test for-do"
(do (do (do (do (do (do (do (do (do (setv (, x y) (, 0 0)))))))))))
(for [[- [1 2]]]
(for [- [1 2]]
(do
(setv x (+ x 1))
(setv y (+ y 1))))
@ -646,7 +646,7 @@
(defn test-nested-if []
"NATIVE: test nested if"
(for [[x (range 10)]]
(for [x (range 10)]
(if (in "foo" "foobar")
(do
(if true true true))
@ -810,14 +810,14 @@
(defn test-break-breaking []
"NATIVE: test checking if break actually breaks"
(defn holy-grail [] (for [[x (range 10)]] (if (= x 5) (break))) x)
(defn holy-grail [] (for [x (range 10)] (if (= x 5) (break))) x)
(assert (= (holy-grail) 5)))
(defn test-continue-continuation []
"NATIVE: test checking if continue actually continues"
(setv y [])
(for [[x (range 10)]]
(for [x (range 10)]
(if (!= x 5)
(continue))
(.append y x))