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:
parent
8cabf22749
commit
eeef65b505
2
NEWS
2
NEWS
@ -55,8 +55,6 @@ Changes from Hy 0.9.11
|
|||||||
|
|
||||||
|
|
||||||
[ Syntax Fixes ]
|
[ Syntax Fixes ]
|
||||||
* for changed syntax from (for [] ...) -> (for [[]] ...)
|
|
||||||
* with changed syntax from (with [] ...) -> (with [[]] ...)
|
|
||||||
* get allows multiple arguments
|
* get allows multiple arguments
|
||||||
|
|
||||||
|
|
||||||
|
@ -205,7 +205,8 @@ however is called only for every other value in the list.
|
|||||||
;; assuming that (side-effect1) and (side-effect2) are functions and
|
;; assuming that (side-effect1) and (side-effect2) are functions and
|
||||||
;; collection is a list of numerical values
|
;; collection is a list of numerical values
|
||||||
|
|
||||||
(for (x collection) (do
|
(for [x collection]
|
||||||
|
(do
|
||||||
(side-effect1 x)
|
(side-effect1 x)
|
||||||
(if (% x 2)
|
(if (% x 2)
|
||||||
(continue))
|
(continue))
|
||||||
@ -489,10 +490,10 @@ collection and calls side-effect to each element in the collection:
|
|||||||
.. code-block:: clj
|
.. code-block:: clj
|
||||||
|
|
||||||
;; assuming that (side-effect) is a function that takes a single parameter
|
;; 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 can have an optional else block
|
||||||
(for [[element collection]] (side-effect element)
|
(for [element collection] (side-effect element)
|
||||||
(else (side-effect-2)))
|
(else (side-effect-2)))
|
||||||
|
|
||||||
The optional `else` block is executed only if the `for` loop terminates
|
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
|
.. code-block:: clj
|
||||||
|
|
||||||
=> (for [[element [1 2 3]]] (if (< element 3)
|
=> (for [element [1 2 3]] (if (< element 3)
|
||||||
... (print element)
|
... (print element)
|
||||||
... (break))
|
... (break))
|
||||||
... (else (print "loop finished")))
|
... (else (print "loop finished")))
|
||||||
1
|
1
|
||||||
2
|
2
|
||||||
|
|
||||||
=> (for [[element [1 2 3]]] (if (< element 4)
|
=> (for [element [1 2 3]] (if (< element 4)
|
||||||
... (print element)
|
... (print element)
|
||||||
... (break))
|
... (break))
|
||||||
... (else (print "loop finished")))
|
... (else (print "loop finished")))
|
||||||
@ -680,7 +681,7 @@ function is defined and passed to another function for filtering output.
|
|||||||
... {:name "Dave" :age 5}])
|
... {:name "Dave" :age 5}])
|
||||||
|
|
||||||
=> (defn display-people [people filter]
|
=> (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)))
|
=> (display-people people (fn [person] (< (:age person) 25)))
|
||||||
Alice
|
Alice
|
||||||
|
@ -7,5 +7,5 @@
|
|||||||
|
|
||||||
(with-as (ThreadPoolExecutor 10) executor
|
(with-as (ThreadPoolExecutor 10) executor
|
||||||
(setv jobs (list-comp (.submit executor task-to-do) (x (range 0 10))))
|
(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)))
|
(.result future)))
|
||||||
|
@ -31,14 +31,14 @@
|
|||||||
|
|
||||||
(defmacro ap-each [lst &rest body]
|
(defmacro ap-each [lst &rest body]
|
||||||
"Evaluate the body form for each element in the list."
|
"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]
|
(defmacro ap-each-while [lst form &rest body]
|
||||||
"Evalutate the body form for each element in the list while the
|
"Evalutate the body form for each element in the list while the
|
||||||
predicate form evaluates to True."
|
predicate form evaluates to True."
|
||||||
`(let [[p (lambda [it] ~form)]]
|
`(let [[p (lambda [it] ~form)]]
|
||||||
(for [[it ~lst]]
|
(for [it ~lst]
|
||||||
(if (p it)
|
(if (p it)
|
||||||
~@body
|
~@body
|
||||||
(break)))))
|
(break)))))
|
||||||
@ -47,7 +47,7 @@
|
|||||||
(defmacro ap-map [form lst]
|
(defmacro ap-map [form lst]
|
||||||
"Yield elements evaluated in the form for each element in the list."
|
"Yield elements evaluated in the form for each element in the list."
|
||||||
`(let [[f (lambda [it] ~form)]]
|
`(let [[f (lambda [it] ~form)]]
|
||||||
(for [[v ~lst]]
|
(for [v ~lst]
|
||||||
(yield (f v)))))
|
(yield (f v)))))
|
||||||
|
|
||||||
|
|
||||||
@ -55,7 +55,7 @@
|
|||||||
"Yield elements evaluated for each element in the list when the
|
"Yield elements evaluated for each element in the list when the
|
||||||
predicate function returns True."
|
predicate function returns True."
|
||||||
`(let [[f (lambda [it] ~rep)]]
|
`(let [[f (lambda [it] ~rep)]]
|
||||||
(for [[it ~lst]]
|
(for [it ~lst]
|
||||||
(if (~predfn it)
|
(if (~predfn it)
|
||||||
(yield (f it))
|
(yield (f it))
|
||||||
(yield it)))))
|
(yield it)))))
|
||||||
@ -64,7 +64,7 @@
|
|||||||
(defmacro ap-filter [form lst]
|
(defmacro ap-filter [form lst]
|
||||||
"Yield elements returned when the predicate form evaluates to True."
|
"Yield elements returned when the predicate form evaluates to True."
|
||||||
`(let [[pred (lambda [it] ~form)]]
|
`(let [[pred (lambda [it] ~form)]]
|
||||||
(for [[val ~lst]]
|
(for [val ~lst]
|
||||||
(if (pred val)
|
(if (pred val)
|
||||||
(yield val)))))
|
(yield val)))))
|
||||||
|
|
||||||
|
@ -25,16 +25,29 @@
|
|||||||
;;; These macros form the hy language
|
;;; These macros form the hy language
|
||||||
;;; They are automatically required in every module, except inside hy.core
|
;;; 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]
|
(defmacro for [args &rest body]
|
||||||
"shorthand for nested for loops:
|
"shorthand for nested for loops:
|
||||||
(for [[x foo] [y bar]] baz) ->
|
(for [x foo
|
||||||
|
y bar]
|
||||||
|
baz) ->
|
||||||
(for* [x foo]
|
(for* [x foo]
|
||||||
(for* [y bar]
|
(for* [y bar]
|
||||||
baz))"
|
baz))"
|
||||||
|
|
||||||
|
(if (odd? (len args))
|
||||||
|
(macro-error args "`for' requires an even number of args."))
|
||||||
|
|
||||||
(if (empty? body)
|
(if (empty? body)
|
||||||
(macro-error None "`for' requires a body to evaluate"))
|
(macro-error None "`for' requires a body to evaluate"))
|
||||||
(if args
|
(if args
|
||||||
`(for* ~(.pop args 0) (for ~args ~@body))
|
`(for* [~(.pop args 0) ~(.pop args 0)]
|
||||||
|
(for ~args ~@body))
|
||||||
`(do ~@body)))
|
`(do ~@body)))
|
||||||
|
|
||||||
|
|
||||||
@ -44,8 +57,16 @@
|
|||||||
(with* [x foo]
|
(with* [x foo]
|
||||||
(with* [y bar]
|
(with* [y bar]
|
||||||
baz))"
|
baz))"
|
||||||
(if args
|
|
||||||
`(with* ~(.pop args 0) (with ~args ~@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)))
|
`(do ~@body)))
|
||||||
|
|
||||||
|
|
||||||
|
@ -313,7 +313,7 @@ def test_ast_valid_while():
|
|||||||
|
|
||||||
def test_ast_valid_for():
|
def test_ast_valid_for():
|
||||||
"Make sure AST can compile 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():
|
def test_ast_invalid_for():
|
||||||
@ -452,14 +452,14 @@ def test_for_compile_error():
|
|||||||
assert(False)
|
assert(False)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
can_compile("(fn [] (for [[x]]))")
|
can_compile("(fn [] (for [x]))")
|
||||||
except HyTypeError as e:
|
except HyTypeError as e:
|
||||||
assert(e.message == "`for' requires a body to evaluate")
|
assert(e.message == "`for' requires an even number of args.")
|
||||||
else:
|
else:
|
||||||
assert(False)
|
assert(False)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
can_compile("(fn [] (for [[x xx]]))")
|
can_compile("(fn [] (for [x xx]))")
|
||||||
except HyTypeError as e:
|
except HyTypeError as e:
|
||||||
assert(e.message == "`for' requires a body to evaluate")
|
assert(e.message == "`for' requires a body to evaluate")
|
||||||
else:
|
else:
|
||||||
|
@ -31,12 +31,12 @@
|
|||||||
(defn test-for-loop []
|
(defn test-for-loop []
|
||||||
"NATIVE: test for loops?"
|
"NATIVE: test for loops?"
|
||||||
(setv count 0)
|
(setv count 0)
|
||||||
(for [[x [1 2 3 4 5]]]
|
(for [x [1 2 3 4 5]]
|
||||||
(setv count (+ count x)))
|
(setv count (+ count x)))
|
||||||
(assert (= count 15))
|
(assert (= count 15))
|
||||||
(setv count 0)
|
(setv count 0)
|
||||||
(for [[x [1 2 3 4 5]]
|
(for [x [1 2 3 4 5]
|
||||||
[y [1 2 3 4 5]]]
|
y [1 2 3 4 5]]
|
||||||
(setv count (+ count x y)))
|
(setv count (+ count x y)))
|
||||||
(assert (= count 150)))
|
(assert (= count 150)))
|
||||||
|
|
||||||
@ -404,9 +404,9 @@
|
|||||||
|
|
||||||
(defn test-yield []
|
(defn test-yield []
|
||||||
"NATIVE: test yielding"
|
"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)
|
(setv ret 0)
|
||||||
(for [[y (gen)]] (setv ret (+ ret y)))
|
(for [y (gen)] (setv ret (+ ret y)))
|
||||||
(assert (= ret 10)))
|
(assert (= ret 10)))
|
||||||
|
|
||||||
|
|
||||||
@ -463,7 +463,7 @@
|
|||||||
(defn test-for-doodle []
|
(defn test-for-doodle []
|
||||||
"NATIVE: test for-do"
|
"NATIVE: test for-do"
|
||||||
(do (do (do (do (do (do (do (do (do (setv (, x y) (, 0 0)))))))))))
|
(do (do (do (do (do (do (do (do (do (setv (, x y) (, 0 0)))))))))))
|
||||||
(for [[- [1 2]]]
|
(for [- [1 2]]
|
||||||
(do
|
(do
|
||||||
(setv x (+ x 1))
|
(setv x (+ x 1))
|
||||||
(setv y (+ y 1))))
|
(setv y (+ y 1))))
|
||||||
@ -646,7 +646,7 @@
|
|||||||
|
|
||||||
(defn test-nested-if []
|
(defn test-nested-if []
|
||||||
"NATIVE: test nested if"
|
"NATIVE: test nested if"
|
||||||
(for [[x (range 10)]]
|
(for [x (range 10)]
|
||||||
(if (in "foo" "foobar")
|
(if (in "foo" "foobar")
|
||||||
(do
|
(do
|
||||||
(if true true true))
|
(if true true true))
|
||||||
@ -810,14 +810,14 @@
|
|||||||
|
|
||||||
(defn test-break-breaking []
|
(defn test-break-breaking []
|
||||||
"NATIVE: test checking if break actually breaks"
|
"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)))
|
(assert (= (holy-grail) 5)))
|
||||||
|
|
||||||
|
|
||||||
(defn test-continue-continuation []
|
(defn test-continue-continuation []
|
||||||
"NATIVE: test checking if continue actually continues"
|
"NATIVE: test checking if continue actually continues"
|
||||||
(setv y [])
|
(setv y [])
|
||||||
(for [[x (range 10)]]
|
(for [x (range 10)]
|
||||||
(if (!= x 5)
|
(if (!= x 5)
|
||||||
(continue))
|
(continue))
|
||||||
(.append y x))
|
(.append y x))
|
||||||
|
Loading…
Reference in New Issue
Block a user