Skip to content

Commit

Permalink
Merge pull request #114 from Kodiologist/misc
Browse files Browse the repository at this point in the history
Miscellany
  • Loading branch information
Kodiologist authored Feb 2, 2025
2 parents 4620534 + 091a10b commit 1c95ebc
Show file tree
Hide file tree
Showing 13 changed files with 117 additions and 160 deletions.
12 changes: 12 additions & 0 deletions NEWS.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,18 @@ Removals
------------------------------
* `defn/a+` has been removed. Use `(defn+ :async …)` instead.
* `fn/a+` has been removed. Use `(fn+ :async …)` instead.
* `profile/calls` has been removed. Use `pycallgraph2` or
`python-call-graph`, which are available on PyPI, instead.
* `profile/cpu` has been removed. Use `(with [pr (cProfile.Profile)]
…)` instead.

Other Breaking Changes
------------------------------
* `(with-gensyms [a b c] …)` is now written `(def-gensyms a b c) …`.
* The names of gensyms produced by `import-path` have changed. (This
shouldn't break your code unless you're doing something
exceptionally weird, but the argument to `hy.gensym` was documented,
so this is technically a breaking change.)

Bug Fixes
------------------------------
Expand Down
4 changes: 1 addition & 3 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -97,13 +97,13 @@ API
.. hy:automodule:: hyrule.macrotools
.. hy:autotag:: /
.. hy:automacro:: def-gensyms
.. hy:automacro:: defmacro-kwargs
.. hy:automacro:: defmacro!
.. hy:autofunction:: macroexpand-all
.. hy:autofunction:: map-hyseq
.. hy:autofunction:: map-model
.. hy:autofunction:: match-fn-params
.. hy:automacro:: with-gensyms
``oop`` — Tools for object-oriented programming
----------------------------------------------------------------------
Expand Down Expand Up @@ -144,8 +144,6 @@ API
.. hy:autofunction:: import-path
.. hy:automacro:: of
.. hy:autofunction:: parse-args
.. hy:automacro:: profile/calls
.. hy:automacro:: profile/cpu
.. hy:automacro:: pun
.. hy:autofunction:: sign
.. hy:automacro:: smacrolet
Expand Down
4 changes: 2 additions & 2 deletions hyrule/anaphoric.hy
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ easier to read. An anaphoric macro assigns values to designated symbols


(require
hyrule.macrotools [defmacro!]
hyrule.macrotools [defmacro! def-gensyms]
hyrule.argmove [->])


Expand Down Expand Up @@ -100,7 +100,7 @@ easier to read. An anaphoric macro assigns values to designated symbols
there is no such element. ::
(ap-last (> it 5) (range 10)) ; => 9"
(setv x (hy.gensym))
(def-gensyms x)
`(let [it None]
(setv ~x None)
(for [it ~xs :if ~form]
Expand Down
6 changes: 4 additions & 2 deletions hyrule/argmove.hy
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
also known as arrow macros."


(require
hyrule.macrotools [def-gensyms])
(import
hyrule.iterables [rest]
itertools [chain])
Expand Down Expand Up @@ -116,7 +118,7 @@ also known as arrow macros."
(.get {"a" 1 "b" 2} char))
(some-> "q" lookup (print "is the value"))
; Prints nothing, since `(lookup "q")` returns `None`.]]
(setv val (hy.gensym))
(def-gensyms val)
`(cond (is (setx ~val ~head) None) None
~@(chain.from_iterable (gfor node args
[`(is (setx ~val (hy.R.hyrule.-> ~val ~node)) None) None]))
Expand Down Expand Up @@ -144,7 +146,7 @@ also known as arrow macros."
(doto [] (.append 1) (.append 2) (.reverse)) ; => [2 1]"

(setv f (hy.gensym))
(def-gensyms f)
(defn build-form [expression]
(setv expression (_dotted expression))
(if (isinstance expression hy.models.Expression)
Expand Down
28 changes: 15 additions & 13 deletions hyrule/control.hy
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
(require
hyrule.macrotools [defmacro!])
hyrule.macrotools [defmacro! def-gensyms])
(import
hyrule.collections [by2s]
hyrule.iterables [coll?]
Expand Down Expand Up @@ -123,7 +123,7 @@
; the key exactly once.
(when (% (len rest) 2)
(raise (TypeError "each test-form needs a result-form")))
(setv x (hy.gensym "case-key"))
(def-gensyms x)
`(do
(setv ~x ~key)
(cond ~@(sum
Expand All @@ -147,7 +147,7 @@


(defn _do-n [count-form body]
(setv count (hy.gensym))
(def-gensyms count)
`(do
(setv ~count ~count-form)
(for [~(hy.gensym)
Expand Down Expand Up @@ -179,21 +179,20 @@
``sys.argv`` is always the name of the script being invoked, whereas the rest
are command-line arguments. If ``args`` is ``[]``, this will be treated like
``[#* _]``, so any command-line arguments (and the script name) will be
allowed, but ignored.
allowed, but ignored. ::
(defmain [program-name argument]
(print "Welcome to" program-name)
(print "The answer is" (* (float argument) 2)))
If the defined function returns an :class:`int`, :func:`sys.exit` is called
with that integer as the return code.
If you want fancy command-line arguments, you can use the standard Python
module :mod:`argparse` in the usual way, because ``defmain`` doesn't change
``sys.argv``. See also :hy:func:`parse-args`. ::
``sys.argv``. See also :hy:func:`parse-args`.]]

(defmain [program-name argument]
(print "Welcome to" program-name)
(print "The answer is" (* (float argument) 2)))]]

(setv retval (hy.gensym)
restval (hy.gensym))
(def-gensyms retval restval)
`(when (= __name__ "__main__")
(import sys)
(setv ~retval ((fn [~@(or args `[#* ~restval])] ~@body) #* sys.argv))
Expand Down Expand Up @@ -247,7 +246,7 @@
(setv counter 0)
(list-n 5 (+= counter 1) counter) ; => [1 2 3 4 5]"
(setv l (hy.gensym))
(def-gensyms l)
`(do
(setv ~l [])
~(_do-n count-form [`(.append ~l (do ~@body))])
Expand All @@ -264,13 +263,16 @@
With ``loop``, this would be written as::
(require hyrule [loop])
(import hyrule [recur])
(defn factorial [n]
(loop [[n n] [acc 1]]
(if n
(recur (- n 1) (* acc n))
acc)))
Don't forget to ``(import hyrule [recur])``. The :hy:class:`recur` object holds the arguments for the next call. When the function returns a :hy:class:`recur`, ``loop`` calls it again with the new arguments. Otherwise, ``loop`` ends and the final value is returned. Thus, what would be a nested set of recursive calls becomes a series of calls that are resolved entirely in sequence.
The :hy:class:`recur` object holds the arguments for the next call. When the function returns a :hy:class:`recur`, ``loop`` calls it again with the new arguments. Otherwise, ``loop`` ends and the final value is returned. Thus, what would be a nested set of recursive calls becomes a series of calls that are resolved entirely in sequence.
Note that while ``loop`` uses the same syntax as ordinary function definitions for its lambda list, all parameters other than ``#* args`` and ``#** kwargs`` must have a default value, because the function will first be called with no arguments."

Expand Down
19 changes: 9 additions & 10 deletions hyrule/destructure.hy
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ Iterator patterns are specified with a :class:`hy.models.Expression`. They work
(require
hyrule.argmove [->>]
hyrule.control [unless branch]
hyrule.macrotools [defmacro!])
hyrule.macrotools [defmacro! def-gensyms])
(import
itertools [starmap chain count]
functools [reduce]
Expand Down Expand Up @@ -158,8 +158,8 @@ Take pairs of destructuring patterns and input data structures, and return a dic
{"apple" 1 "banana" 2})
; => {'a 1 'b 2}]]

(setv gsyms []
result (hy.gensym 'dict=:))
(setv gsyms [])
(def-gensyms result)
`(do
(setv ~result {}
~@(gfor [binds expr] (by2s pairs)
Expand All @@ -184,8 +184,8 @@ Take pairs of destructuring patterns and input data structures, and return a dic
and :as must be last, if present.
"
(defn dispatch [f]
(setv dcoll (hy.gensym f.__name__)
result [dcoll expr]
(def-gensyms dcoll)
(setv result [dcoll expr]
seen #{})
(defn found [magic target]
(when (= magic target)
Expand Down Expand Up @@ -320,9 +320,8 @@ Take pairs of destructuring patterns and input data structures, and return a dic
``itertools.tee`` to ``foo``.
For example, try ``(destructure '(a b c :& more :as it) (count))``.
"
(setv [bs magics] (find-magics binds)
copy-iter (hy.gensym)
tee (hy.gensym))
(setv [bs magics] (find-magics binds))
(def-gensyms copy-iter tee)
(if (in ':as (sfor [x #* _] magics x))
(.extend result [diter `(do
(import itertools [tee :as ~tee])
Expand All @@ -345,7 +344,7 @@ Take pairs of destructuring patterns and input data structures, and return a dic
s)))))

(defmacro defn+ [#* args]
"As :hy:func:`defn`, but the lambda list is destructured as a list pattern. The usual special parameter names in lambda lists, such as `#*`, aren't special here. No type annotations are allowed are in the lambda list, but a return-value annotation for the whole function is allowed."
"As :hy:func:`defn`, but the lambda list is destructured as a list pattern. The usual special parameter names in lambda lists, such as ``#*``, aren't special here. No type annotations are allowed are in the lambda list, but a return-value annotation for the whole function is allowed."
(destructuring-fn 'defn args))

(defmacro fn+ [#* args]
Expand All @@ -354,7 +353,7 @@ Take pairs of destructuring patterns and input data structures, and return a dic

(defn destructuring-fn [like args]
(setv [headers params doc body] (parse-defn-like like args))
(setv args (hy.gensym) kwargs (hy.gensym))
(def-gensyms args kwargs)
`(~@headers [#* ~args #** ~kwargs]
~doc
~(_expanded-setv params args kwargs)
Expand Down
10 changes: 5 additions & 5 deletions hyrule/iterables.hy
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

(defn coll? [x]
#[[Return ``True`` if ``x`` inherits from :class:`collections.abc.Iterable`
but not ``str`` or ``bytes``. ::
but not :class:`str` or :class:`bytes`. ::
(coll? ["abc"]) ; True
(coll? {"a" 1 "b" 2}) ; True
Expand All @@ -29,7 +29,7 @@
(defn distinct [coll]
"Return an iterator from the original iterable ``coll`` with no
duplicates. Duplicates are detected by calling :hy:func:`in
<hy.pyops.in>` on a :class:`set`. Elements will be produced in order
<hy.pyops.in>` on a :class:`set`. Elements are produced in order
of their first appearance in ``coll``. ::
(list (distinct [1 2 3 4 3 5 0 2])) ; => [1 2 3 4 5 0]"
Expand Down Expand Up @@ -95,11 +95,11 @@
arguments as ``range``, but includes the endpoint (given a
compatible start point and step size). ::
(thru 3)
(list (thru 3))
; => [0 1 2 3]
(thru 0 10 2)
(list (thru 0 10 2))
; => [0 2 4 6 8 10]
(thru 0 9 2)
(list (thru 0 9 2))
; => [0 2 4 6 8]"

(when (is b None)
Expand Down
60 changes: 28 additions & 32 deletions hyrule/macrotools.hy
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,26 @@
hyrule.iterables [coll? flatten])


(defmacro def-gensyms [#* symbols]

#[[Define a number of gensyms, binding each symbol to a call to
:hy:func:`hy.gensym`. The syntax ::
(def-gensyms a b c)
is equivalent to ::
(setv
a (hy.gensym 'a)
b (hy.gensym 'b)
c (hy.gensym 'c))]]

`(setv ~@(gfor
sym symbols
x [sym `(hy.gensym '~sym)]
x)))


(defmacro defmacro-kwargs [name params #* body]

#[=[Define a macro that can take keyword arguments. When the macro
Expand All @@ -12,7 +32,7 @@
local variables that can be used in the macro body. ::

(defmacro-kwargs do10times [form [print-iteration 'False]]
(setv i (hy.gensym))
(def-gensyms i)
`(for [~i (range 10)]
(when ~print-iteration
(print "Now on iteration:" ~i))
Expand All @@ -31,7 +51,7 @@
(setv docstring None)
(when (and body (isinstance (get body 0) hy.models.String))
(setv [docstring #* body] body))
(setv g (hy.gensym))
(def-gensyms g)
`(defmacro ~name [#* ~g]
~@(if docstring [docstring] [])
(setv ~g (hy.I.hyrule.match-fn-params ~g '~params))
Expand All @@ -45,11 +65,11 @@

(defn match-fn-params [args params]
#[[Match an iterable of arguments against a parameter list in the
style of a :hy:func:`defn` lambda list. The parameter-list syntax
here is somewhat restricted: annotations are forbiddden, ``/`` and
``*`` aren't recognized, and nothing is allowed after ``#* args``
other than ``#** kwargs``. Return a dictionary of the parameters and
their values. ::
style of a :hy:func:`defn` lambda list. Return a dictionary of the
parameters and their values. The parameter-list syntax here is
somewhat restricted: annotations are forbiddden, ``/`` and ``*``
aren't recognized, and nothing is allowed after ``#* args`` other
than ``#** kwargs``. ::
(match-fn-params
[1 :foo "x"]
Expand Down Expand Up @@ -298,7 +318,7 @@
(+= FOO (ABS -5)))
(print foo) ; => 20
That's why the parameters of ``map-model`` are backwards compared to ``map``: in user code, ``x`` is typically a symbol or other simple form whereas ``f`` is a multi-line anonymous function.]]
That's why the parameters of ``map-model`` are backwards compared to :func:`map`: in user code, ``x`` is typically a symbol or other simple form whereas ``f`` is a multi-line anonymous function.]]

(_map-model (hy.as-model x) f))

Expand Down Expand Up @@ -333,30 +353,6 @@
x))


(defmacro with-gensyms [args #* body]

#[[Evaluate ``body`` with each name in ``args`` (a list of symbols) bound to
a gensym. The syntax ::
(with-gensyms [a b c]
…)
is equivalent to ::
(do
(setv a (hy.gensym 'a))
(setv b (hy.gensym 'b))
(setv c (hy.gensym 'c))
…)]]

(setv syms [])
(for [arg args]
(.extend syms [arg `(hy.gensym '~arg)]))
`(do
(setv ~@syms)
~@body))


(defreader /

#[[Read one identifier and interpret it as a one-shot import in the same
Expand Down
Loading

0 comments on commit 1c95ebc

Please sign in to comment.