%* %** parameters for #% tag macro

This commit is contained in:
gilch 2017-10-22 21:36:30 -06:00
parent f81fb771eb
commit b5f1136ba5
4 changed files with 34 additions and 24 deletions

3
NEWS
View File

@ -22,7 +22,8 @@ Changes from 0.13.0
* support EDN `#_` syntax to discard the next term * support EDN `#_` syntax to discard the next term
* `return` has been implemented as a special form * `return` has been implemented as a special form
* `while` loops may now contain an `else` clause, like `for` loops * `while` loops may now contain an `else` clause, like `for` loops
* `xi` from `hy.extra.anaphoric` is now the `#%` tag macro. * `xi` from `hy.extra.anaphoric` is now the `#%` tag macro
* `#%` also has a new `&kwargs` parameter `%**`.
[ Bug Fixes ] [ Bug Fixes ]
* Numeric literals are no longer parsed as symbols when followed by a dot * Numeric literals are no longer parsed as symbols when followed by a dot

View File

@ -236,16 +236,17 @@ Returns a function which applies several forms in series from left to right. The
Usage ``#%(body ...)`` Usage ``#%(body ...)``
Returns a function with parameters implicitly determined by the presence in Makes a function with an implicit parameter list from ``%`` parameters.
the body of %i parameters. A %i symbol designates the ith parameter
(1-based, e.g. ``%1 %2 %3`` etc.), or all remaining parameters for ``%&``. A ``%i`` symbol designates the `i` th parameter (1-based, e.g. ``%1 %2 %3`` etc.).
``%*`` and ``%**`` name the ``&rest`` and ``&kwargs`` parameters, respectively.
Nesting of ``#%()`` forms is not recommended. Nesting of ``#%()`` forms is not recommended.
This is similar to Clojure's anonymous function literals (``#()``). This is similar to Clojure's anonymous function literals (``#()``).
.. code-block:: hy .. code-block:: hy
=> (#%(identity [%1 %5 [%2 %3] %& %4]) 1 2 3 4 5 6 7 8) => (#%(identity [%1 %5 [%2 %3] %* %4]) 1 2 3 4 5 6 7 8)
[1, 5, [2, 3,] (6, 7, 8), 4] [1, 5, [2, 3,] (6, 7, 8), 4]
=> (def add-10 #%(+ 10 %1)) => (def add-10 #%(+ 10 %1))
=> (add-10 6) => (add-10 6)

View File

@ -113,24 +113,28 @@
`(fn [var] (ap-pipe var ~@forms))) `(fn [var] (ap-pipe var ~@forms)))
(deftag % [body] (deftag % [body]
"Returns a function with parameters implicitly determined by the presence in "makes a function with an implicit parameter list from `%` parameters.
the body of %i parameters. A %i symbol designates the ith parameter
(1-based, e.g. %1, %2, %3, etc.), or all remaining parameters for %&. A %i symbol designates the ith parameter (1-based, e.g. `%1 %2 %3` etc.).
Nesting of #%() forms is not recommended." `%*` and `%**` name the `&rest` and `&kwargs` parameters, respectively.
Nesting of `#%()` forms is not recommended."
(setv flatbody (flatten body)) (setv flatbody (flatten body))
`(fn [;; generate all %i symbols up to the maximum found in body `(fn [;; generate all %i symbols up to the maximum found in body
~@(genexpr (HySymbol (+ "%" ~@(genexpr (HySymbol (+ "%"
(str i))) (str i)))
[i (range 1 [i (range 1
;; find the maximum %i ;; find the maximum %i
(inc (max (+ (list-comp (int (cut a 1)) (-> (list-comp (int (cut a 1))
[a flatbody] [a flatbody]
(and (symbol? a) (and (symbol? a)
(.startswith a '%) (.startswith a '%)
(.isdigit (cut a 1)))) (.isdigit (cut a 1))))
[0]))))]) (+ [0])
;; generate the &rest parameter only if '%& is present in body max
~@(if (in '%& flatbody) inc))])
'(&rest %&) ;; generate the &rest parameter only if '%* is present in body
'())] ~@(if (in '%* flatbody)
'(&rest %*))
~@(if (in '%** flatbody)
'(&kwargs %**))]
(~@body))) (~@body)))

View File

@ -108,19 +108,23 @@
(assert-equal (#%(identity (, %1 %2 %3 %4 %5)) 1 2 3 4 5) (, 1 2 3 4 5)) (assert-equal (#%(identity (, %1 %2 %3 %4 %5)) 1 2 3 4 5) (, 1 2 3 4 5))
(assert-equal (#%(identity (, %1 %5 %2 %3 %4)) 1 2 3 4 5) (, 1 5 2 3 4)) (assert-equal (#%(identity (, %1 %5 %2 %3 %4)) 1 2 3 4 5) (, 1 5 2 3 4))
;; test &rest ;; test &rest
(assert-equal (#%(sum %&) 1 2 3) 6) (assert-equal (#%(sum %*) 1 2 3) 6)
(assert-equal (#%(identity (, %1 %&)) 10 1 2 3) (, 10 (, 1 2 3))) (assert-equal (#%(identity (, %1 %*)) 10 1 2 3) (, 10 (, 1 2 3)))
;; no parameters ;; no parameters
(assert-equal (#%(list)) []) (assert-equal (#%(list)) [])
(assert-equal (#%(identity "Hy!")) "Hy!") (assert-equal (#%(identity "Hy!")) "Hy!")
(assert-equal (#%(identity "%&")) "%&") (assert-equal (#%(identity "%*")) "%*")
(assert-equal (#%(+ "Hy " "world!")) "Hy world!") (assert-equal (#%(+ "Hy " "world!")) "Hy world!")
;; test skipped parameters ;; test skipped parameters
(assert-equal (#%(identity [%3 %1]) 1 2 3) [3 1]) (assert-equal (#%(identity [%3 %1]) 1 2 3) [3 1])
;; test nesting ;; test nesting
(assert-equal (#%(identity [%1 (, %2 [%3] "Hy" [%&])]) 1 2 3 4 5) (assert-equal (#%(identity [%1 (, %2 [%3] "Hy" [%*])]) 1 2 3 4 5)
[1 (, 2 [3] "Hy" [(, 4 5)])]) [1 (, 2 [3] "Hy" [(, 4 5)])])
;; test arg as function ;; test arg as function
(assert-equal (#%(%1 2 4) +) 6) (assert-equal (#%(%1 2 4) +) 6)
(assert-equal (#%(%1 2 4) -) -2) (assert-equal (#%(%1 2 4) -) -2)
(assert-equal (#%(%1 2 4) /) 0.5)) (assert-equal (#%(%1 2 4) /) 0.5)
;; test &rest &kwargs
(assert-equal (#%(, %* %**) 1 2 :a 'b)
(, (, 1 2)
(dict :a 'b))))