API reference¶
This chapter describes most of Hy's public-facing macros, functions, and classes. It refers to Python's own documentation when appropriate rather than recapitulating the details of Python semantics.
Core macros¶
The following macros are automatically imported into all Hy modules as their
base names, such that hy.core.macros.foo
can be called as just foo
.
Macros that are also available as functions are described as functions
under Python operators.
Fundamentals¶
- macro(do #* body)¶
do
(calledprogn
in some Lisps) takes any number of forms, evaluates them, and returns the value of the last one, orNone
if no forms were provided.(+ 1 (do (setv x (+ 1 1)) x)) ; => 3
- macro(do-mac #* body)¶
do-mac
evaluates its arguments (in order) at compile time, and leaves behind the value of the last argument (None
if no arguments were provided) as code to be run. The effect is similar to defining and then immediately calling a nullary macro, hence the name, which stands for "do macro".(do-mac `(setv ~(hy.models.Symbol (* "x" 5)) "foo")) ; Expands to: (setv xxxxx "foo") (print xxxxx) ; => "foo"
Contrast with
eval-and-compile
, which evaluates the same code at compile-time and run-time, instead of using the result of the compile-time run as code for run-time.do-mac
is also similar to Common Lisp's SHARPSIGN DOT syntax (#.
), from which it differs by evaluating at compile-time rather than read-time.
- macro(eval-and-compile #* body)¶
eval-and-compile
takes any number of forms as arguments. The input forms are evaluated as soon as theeval-and-compile
form is compiled, then left in the program so they can be executed at run-time as usual; contrast witheval-when-compile
. So, if you compile and immediately execute a program (as callinghy foo.hy
does whenfoo.hy
doesn't have an up-to-date byte-compiled version),eval-and-compile
forms will be evaluated twice. For example, the following program(eval-when-compile (print "Compiling")) (print "Running") (eval-and-compile (print "Hi"))
prints
Compiling Hi Running Hi
The return value of
eval-and-compile
is its final argument, as fordo
.One possible use of
eval-and-compile
is to make a function available both at compile-time (so a macro can call it while expanding) and run-time (so it can be called like any other function):(eval-and-compile (defn add [x y] (+ x y))) (defmacro m [x] (add x 2)) (print (m 3)) ; prints 5 (print (add 3 6)) ; prints 9
Had the
defn
not been wrapped ineval-and-compile
,m
wouldn't be able to calladd
, because when the compiler was expanding(m 3)
,add
wouldn't exist yet.While
eval-and-compile
executes the same code at both compile-time and run-time, bear in mind that the same code can have different meanings in the two contexts. Consider, for example, issues of scoping:(eval-when-compile (print "Compiling")) (print "Running") (eval-and-compile (setv x 1)) (defn f [] (setv x 2) (eval-and-compile (setv x 3)) (print "local x =" x)) (f) (eval-and-compile (print "global x =" x))
The form
(setv x 3)
above refers to the globalx
at compile-time, but the localx
at run-time, so the result is:Compiling global x = 3 Running local x = 3 global x = 1
- macro(eval-when-compile #* body)¶
eval-when-compile
executes the given forms at compile-time, but discards them at run-time and simply returnsNone
instead; contrasteval-and-compile
. Hence, whileeval-when-compile
doesn't directly contribute code to the final program, it can change Hy's state while compiling, as by defining a function:(eval-when-compile (defn add [x y] (+ x y))) (defmacro m [x] (add x 2)) (print (m 3)) ; prints 5 (print (add 3 6)) ; raises NameError: name 'add' is not defined
- macro(py string)¶
py
parses the given Python code at compile-time and inserts the result into the generated abstract syntax tree. Thus, you can mix Python code into a Hy program. Only a Python expression is allowed, not statements; usepys
if you want to use Python statements. The value of the expression is returned from thepy
form.(print "A result from Python:" (py "'hello' + 'world'"))
The code must be given as a single string literal, but you can still use macros,
hy.eval
, and related tools to construct thepy
form. If having to backslash-escape internal double quotes is getting you down, try a bracket string. If you want to evaluate some Python code that's only defined at run-time, try the standard Python functioneval()
.The code is implicitly wrapped in parentheses so Python won't give you grief about indentation. After all, Python's indentation rules are only useful for grouping statements, whereas
py
only allows an expression.Python code need not syntactically round-trip if you use hy2py on a Hy program that uses
py
orpys
. For example, comments will be removed.
- macro(pys string)¶
As
py
, but the code can consist of zero or more statements, including compound statements such asfor
anddef
.pys
always returnsNone
.(pys "myvar = 5") (print "myvar is" myvar)
Unlike
py
, no parentheses are added, because Python doesn't allow statements to be parenthesized. Instead, the code string is dedented withtextwrap.dedent()
before parsing. Thus you can indent the code to match the surrounding Hy code when Python would otherwise forbid this, but beware that significant leading whitespace in embedded string literals will be removed.
- macro(pragma #* args)¶
pragma
is used to adjust the state of the compiler. It's called for its side-effects, and returnsNone
. The arguments are key-value pairs, like a function call with keyword arguments:(pragma :prag1 value1 :prag2 (get-value2))
Each key is a literal keyword giving the name of a pragma. Each value is an arbitrary form, which is evaluated as ordinary Hy code but at compile-time.
The effect of each pragma is locally scoped to its containing function, class, or comprehension form (other than
for
), if there is one.Only one pragma is currently implemented:
:warn-on-core-shadow
: If true (the default),defmacro
andrequire
will raise a warning at compile-time if you define a macro with the same name as a core macro. Shadowing a core macro in this fashion is dangerous, because other macros may call your new macro when they meant to refer to the core macro.
Quoting¶
- macro(quote model)¶
Return the given model without evaluating it. Or to be more pedantic,
quote
complies to code that produces and returns the model it was originally called on. Thusquote
serves as syntactic sugar for model constructors:(quote a) ; Equivalent to: (hy.models.Symbol "a") (quote (+ 1 1)) ; Equivalent to: (hy.models.Expression [ ; (hy.models.Symbol "+") ; (hy.models.Integer 1) ; (hy.models.Integer 1)])
quote
itself is conveniently abbreviated as the single-quote character'
, which needs no parentheses, allowing one to instead write:'a '(+ 1 1)
See also:
quasiquote
to substitute values into a quoted formhy.eval
to evaluate models as codehy.repr
to stringify models into Hy source text that uses'
- macro(quasiquote model)¶
- macro(unquote model)¶
- macro(unquote-splice model)¶
quasiquote
is likequote
except that it treats the model as a template, in which certain special expressions indicate that some code should be evaluated and its value substituted there. The idea is similar to C'ssprintf
or Python's various string-formatting constructs. For example:(setv x 2) (quasiquote (+ 1 (unquote x))) ; => '(+ 1 2)
unquote
indicates code to be evaluated, sox
becomes2
and the2
gets inserted in the parent model.quasiquote
can be abbreviated as a backtick (`), with no parentheses, and likewiseunquote
can be abbreviated as a tilde (~
), so one can instead write simply`(+ 1 ~x)
(In the bulk of Lisp tradition, unquotation is written
,
. Hy goes with Clojure's choice of~
, which has the advantage of being more visible in most programming fonts.)Quasiquotation is convenient for writing macros:
(defmacro set-foo [value] `(setv foo ~value)) (set-foo (+ 1 2 3)) (print foo) ; => 6
Another kind of unquotation operator,
unquote-splice
, abbreviated~@
, is analogous tounpack-iterable
in that it splices an iterable object into the sequence of the parent sequential model. Compare the effects ofunquote
tounquote-splice
:(setv X [1 2 3]) (hy.repr `[a b ~X c d ~@X e f]) ; => '[a b [1 2 3] c d 1 2 3 e f]
If
unquote-splice
is given any sort of false value (such asNone
), it's treated as an empty list. To be precise,~@x
splices in the result of(or x [])
.Note that while a symbol name can begin with
@
in Hy,~@
takes precedence in the parser, so if you want to unquote the symbol@foo
with~
, you must use whitespace to separate~
and@
, as in~ @foo
.
Assignment, mutation, and annotation¶
- macro(setv #* args)¶
setv
compiles to an assignment statement (seesetx
for assignment expressions), which sets the value of a variable or some other assignable expression. It requires an even number of arguments, and always returnsNone
. The most common case is two arguments, where the first is a symbol:(setv websites 103) (print websites) ; => 103
Additional pairs of arguments are equivalent to several two-argument
setv
calls, in the given order. Thus, the semantics are like Common Lisp'ssetf
rather thanpsetf
.(setv x 1 y x x 2) (print x y) ; => 2 1
All the same kinds of complex assignment targets are allowed as in Python. So, you can use list assignment to assign in parallel. (As in Python, tuple and list syntax are equivalent for this purpose; Hy differs from Python merely in that its list syntax is shorter than its tuple syntax.)
(setv [x y] [y x]) ; Swaps the values of `x` and `y`
Unpacking assignment looks like this (see
unpack-iterable
):(setv [letter1 letter2 #* others] "abcdefg") (print letter1 letter2 (hy.repr others)) ; => a b ["c" "d" "e" "f" "g"]
See
let
to simulate more traditionally Lispy block-level scoping.
- macro(setx target value)¶
setx
compiles to an assignment expression (PEP 572). Thus, unlikesetv
, it returns the assigned value. It takes exactly two arguments, and the target must be a bare symbol.(when (> (setx x (+ 1 2)) 0) (print x "is greater than 0")) ; => 3 is greater than 0
- macro(let bindings #* body)¶
let
is a macro for simulating traditional block scoping as seen in other Lisps. Since it coexists with ordinary Python scoping, its consequences can be complex, so it's wise to get a solid understanding of Python scoping before you use it. Beginners to Python should note particularly thatsetv
inside a function or class typically creates a local variable, solet
isn't required for local variables or closures as it is in many other Lisps.That disclaimer aside,
let
creates local variables with lexically scoped names. The macro takes a list of binding pairs followed by abody
which gets executed. A let-bound name ceases to refer to that local outside thelet
form, but arguments in nested functions, and bindings in nestedlet
forms, can shadow these names.(let [x 5 y 6] ; Create `x` and `y` (print x y) ; => 5 6 (let [x 7] ; Create a variable that shadows the earlier `x` (print x y)) ; => 7 6 (print x y)) ; => 5 6
The left-hand item of a binding pair is typically a plain symbol, but it can also use extended iterable unpacking (PEP 3132):
(let [[head #* tail] #(0 1 2)] [head tail]) ; => [0 [1 2]]
Basic assignments, as with
setv
or+=
, will update the local variable named by a let binding when they assign to a let-bound name. But assignments viaimport
are always hoisted to normal Python scope, and likewise,defn
ordefclass
will assign the function or class in the Python scope, even if it shares the name of a let binding. To avoid this hoisting, useimportlib.import_module()
,fn
, ortype
(or whatever metaclass) instead.If
lfor
,sfor
,dfor
, orgfor
(but notfor
) is in the body of alet
, assignments in iteration clauses and:setv
clauses will create a new variable in the comprehenion form's own scope, without touching any outer let-bound variable of the same name.Like the
let*
of many other Lisps,let
executes the variable assignments one-by-one, in the order written:(let [x 5 y (+ x 1)] (print x y)) ; => 5 6 (let [x 1 x (fn [] x)] (x)) ; => 1
Note that let-bound variables continue to exist in the surrounding Python scope. As such, let-bound objects may not be eligible for garbage collection as soon as the
let
ends. To ensure there are no references to let-bound objects as soon as possible, usedel
at the end of thelet
, or wrap thelet
in a function.
- macro(global #* syms)¶
global
compiles to aglobal
statement, which declares one or more names as referring to global (i.e., module-level) variables. The arguments are symbols; with no arguments,global
has no effect. The return value is alwaysNone
.(setv a 1 b 10) (print a b) ; => 1 10 (defn f [] (global a) (setv a 2 b 20)) (f) (print a b) ; => 2 10
- macro(nonlocal #* syms)¶
Similar to
global
, but names can be declared in any enclosing scope.nonlocal
compiles to aglobal
statement for any names originally defined in the global scope, and anonlocal
statement for all other names.(setv a 1 b 1) (defn f [] (setv c 10 d 10) (defn g [] (nonlocal a c) (setv a 2 b 2 c 20 d 20)) (print a b c d) ; => 1 1 10 10 (g) (print a b c d)) ; => 2 1 20 10 (f)
- macro(del #* args)¶
del
compiles to adel
statement, which deletes variables or other assignable expressions. It always returnsNone
.(del foo (get mydict "mykey") myobj.myattr)
- macro(annotate value type)¶
annotate
and its shorthand form#^
are used to denote annotations, including type hints, in three different contexts:Standalone variable annotations (PEP 526)
Variable annotations in a
setv
callFunction-parameter annotations (PEP 3107)
The difference between
annotate
and#^
is thatannotate
requires parentheses and takes the name to be annotated first (like Python), whereas#^
doesn't require parentheses (it only applies to the next two forms) and takes the name second:(setv (annotate x int) 1) (setv #^ int x 1)
The order difference is not merely visual:
#^
actually evaluates the type first.Here are examples with
#^
for all the places you can use annotations:; Annotate the variable `x` as an `int` (equivalent to `x: int`). #^ int x ; You can annotate with expressions (equivalent to `y: f(x)`). #^(f x) y ; Annotations with an assignment: each annotation `(int, str)` ; covers the term that immediately follows. ; Equivalent to `x: int = 1; y = 2; z: str = 3` (setv #^ int x 1 y 2 #^ str z 3) ; Annotate `a` as an `int`, `c` as an `int`, and `b` as a `str`. ; Equivalent to `def func(a: int, b: str = None, c: int = 1): ...` (defn func [#^ int a #^ str [b None] #^ int [c 1]] ...) ; Function return annotations come before the function name (if ; it exists). (defn #^ int add1 [#^ int x] (+ x 1)) (fn #^ int [#^ int y] (+ y 2))
For annotating items with generic types, the
of
macro will likely be of use.An issue with type annotations is that, as of this writing, we know of no Python type-checker that can work with
ast
objects or bytecode files. They all need Python source text. So you'll have to translate your Hy with hy2py in order to actually check the types.
- macro(deftype args)¶
deftype
compiles to atype
statement, which defines a type alias. It requires Python 3.12. Its arguments optionally begin with:tp
and a list of type parameters (as indefn
), then specify the name for the new alias and its value.(deftype IntOrStr (| int str)) (deftype :tp [T] ListOrSet (| (get list T) (get set T)))
Subsetting¶
- .¶
The dot macro
.
compiles to one or more attribute references, which select an attribute of an object. The first argument, which is required, can be an arbitrary form. With no further arguments,.
is a no-op. Additional symbol arguments are understood as a chain of attributes, so(. foo bar)
compiles tofoo.bar
, and(. a b c d)
compiles toa.b.c.d
.As a convenience,
.
supports two other kinds of arguments in place of a plain attribute. A parenthesized expression is understood as a method call:(. foo (bar a b))
compiles tofoo.bar(a, b)
. A bracketed form is understood as a subscript:(. foo ["bar"])
compiles tofoo["bar"]
. All these options can be mixed and matched in a single.
call, so(. a (b 1 2) c [d] [(e 3 4)])
compiles to
a.b(1, 2).c[d][e(3, 4)]
Dotted identifiers provide syntactic sugar for common uses of this macro. In particular, syntax like
foo.bar
ends up meaning the same thing in Hy as in Python. Also,get
is another way to subscript in Hy.
- macro(unpack-iterable form)¶
- macro(unpack-mapping form)¶
(Also known as the splat operator, star operator, argument expansion, argument explosion, argument gathering, and varargs, among others...)
unpack-iterable
andunpack-mapping
allow an iterable or mapping object (respectively) to provide positional or keywords arguments (respectively) to a function.=> (defn f [a b c d] [a b c d]) => (f (unpack-iterable [1 2]) (unpack-mapping {"c" 3 "d" 4})) [1 2 3 4]
unpack-iterable
is usually written with the shorthand#*
, andunpack-mapping
with#**
.=> (f #* [1 2] #** {"c" 3 "d" 4}) [1 2 3 4]
Unpacking is allowed in a variety of contexts, and you can unpack more than once in one expression (PEP 3132, PEP 448).
=> (setv [a #* b c] [1 2 3 4 5]) => [a b c] [1 [2 3 4] 5] => [#* [1 2] #* [3 4]] [1 2 3 4] => {#** {1 2} #** {3 4}} {1 2 3 4} => (f #* [1] #* [2] #** {"c" 3} #** {"d" 4}) [1 2 3 4]
Conditionals and basic loops¶
- macro(if test true-value false-value)¶
if
compiles to anif
expression (or compoundif
statement). The formtest
is evaluated and categorized as true or false according tobool
. If the result is true,true-value
is evaluated and returned. Othewise,false-value
is evaluated and returned.(if (has-money-left account) (print "Let's go shopping!") (print "Back to work."))
See also:
- macro(hy.core.macros.when test #* body)¶
Shorthand for
(if test (do …) None)
. Seeif
. For a logically negated version, see Hyrule'sunless
.(when panic (log.write panic) (print "Process returned:" panic.msg) (return panic))
- macro(hy.core.macros.cond #* args)¶
Shorthand for a nested sequence of
if
forms, like anif
-elif
-else
ladder in Python. Syntax such as(cond condition1 result1 condition2 result2)
is equivalent to
(if condition1 result1 (if condition2 result2 None))
Notice that
None
is returned when no conditions match; useTrue
as the final condition to change the fallback result. Usedo
to execute several forms as part of a single condition or result.With no arguments,
cond
returnsNone
. With an odd number of arguments,cond
raises an error.
- macro(while condition #* body)¶
while
compiles to awhile
statement, which executes some code as long as a condition is met. The first argument towhile
is the condition, and any remaining forms constitute the body. It always returnsNone
.(while True (print "Hello world!"))
The last form of a
while
loop can be anelse
clause, which is executed after the loop terminates, unless it exited abnormally (e.g., withbreak
). So,(setv x 2) (while x (print "In body") (-= x 1) (else (print "In else")))
prints
In body In body In else
If you put a
break
orcontinue
form in the condition of awhile
loop, it will apply to the very same loop rather than an outer loop, even if execution is yet to ever reach the loop body. (Hy compiles awhile
loop with statements in its condition by rewriting it so that the condition is actually in the body.) So,(for [x [1]] (print "In outer loop") (while (do (print "In condition") (break) (print "This won't print.") True) (print "This won't print, either.")) (print "At end of outer loop"))
prints
In outer loop In condition At end of outer loop
- macro(break)¶
break
compiles to abreak
statement, which terminates the enclosing loop. The following example has an infinitewhile
loop that ends when the user enters "k":(while True (if (= (input "> ") "k") (break) (print "Try again")))
In a loop with multiple iteration clauses, such as
(for [x xs y ys] …)
,break
only breaks out of the innermost iteration, not the whole form. To jump out of the whole form, enclose it in ablock
and useblock-ret
instead ofbreak
. In the case offor
, but notlfor
and the other comprehension forms, you may also enclose it in a function and usereturn
.
- macro(continue)¶
continue
compiles to acontinue
statement, which returns execution to the start of a loop. In the following example,(.append output x)
is executed on each iteration, whereas(.append evens x)
is only executed for even numbers.(setv output [] evens []) (for [x (range 10)] (.append output x) (when (% x 2) (continue)) (.append evens x))
In a loop with multiple iteration clauses, such as
(for [x xs y ys] …)
,continue
applies to the innermost iteration, not the whole form. To jump to the next step of an outer iteration, try rewriting your loop as multiple nested loops and interposing ablock
, as in(for [x xs] (block (for [y ys] …)))
. You can then useblock-ret
in place ofcontinue
.
Comprehensions¶
- macro(for #* args)¶
for
compiles to one or morefor
statements, which execute code repeatedly for each element of an iterable object. The return values of the forms are discarded and thefor
form returnsNone
.(for [x [1 2 3]] (print "iterating") (print x)) ; Output: iterating 1 iterating 2 iterating 3
The first argument of
for
, in square brackets, specifies how to loop. A simple and common case is[variable values]
, wherevalues
is an iterable object (such as a list) andvariable
is a symbol specifiying the name for each element. Subsequent arguments tofor
are body forms to be evaluated for each iteration of the loop.More generally, the first argument of
for
allows the same types of clauses aslfor
:(for [x [1 2 3] :if (!= x 2) y [7 8]] (print x y)) ; Output: 1 7 1 8 3 7 3 8
In particular, you can use an
:async
clause to get the equivalent of Python'sasync for
:(import asyncio) (defn :async numbers [] (yield 1) (yield 2)) (asyncio.run ((fn :async [] (for [:async x (numbers)] (print x)))))
The last argument of
for
can be an(else …)
form. This form is executed after the last iteration of thefor
's outermost iteration clause, but only if that outermost loop terminates normally. If it's jumped out of with e.g.break
, theelse
is ignored.(for [x [1 2 3]] (print x) (when (= x 2) (break)) (else (print "loop finished")))
- macro(lfor #* args)¶
The comprehension forms
lfor
,sfor
,dfor
,gfor
, andfor
are used to produce various kinds of loops, including Python-style comprehensions.lfor
in particular can create a list comprehension. A simple use oflfor
is:(lfor x (range 5) (* 2 x)) ; => [0 2 4 6 8]
x
is the name of a new variable, which is bound to each element of(range 5)
. Each such element in turn is used to evaluate the value form(* 2 x)
, and the results are accumulated into a list.Here's a more complex example:
(lfor x (range 3) y (range 3) :if (!= x y) :setv total (+ x y) [x y total]) ; => [[0 1 1] [0 2 2] [1 0 1] [1 2 3] [2 0 2] [2 1 3]]
When there are several iteration clauses (here, the pairs of forms
x (range 3)
andy (range 3)
), the result works like a nested loop or Cartesian product: all combinations are considered in lexicographic order.The general form of
lfor
is:(lfor CLAUSES VALUE)
where the
VALUE
is an arbitrary form that is evaluated to produce each element of the result list, andCLAUSES
is any number of clauses. There are several types of clauses:Iteration clauses, which look like
LVALUE ITERABLE
. TheLVALUE
is usually just a symbol, but could be something more complicated, like[x y]
.:async LVALUE ITERABLE
, which is an asynchronous form of iteration clause per Python'sasync for
.:do FORM
, which simply evaluates theFORM
. If you use(continue)
or(break)
here, it will apply to the innermost iteration clause before the:do
.:setv LVALUE RVALUE
, which is equivalent to:do (setv LVALUE RVALUE)
.:if CONDITION
, which is equivalent to:do (when (not CONDITION) (continue))
.
For
lfor
,sfor
,gfor
, anddfor
, variables defined by an iteration clause or:setv
are not visible outside the form. However, variables defined within the body, as with asetx
expression, will be visible outside the form. Infor
, by contrast, iteration and:setv
clauses share the caller's scope and are visible outside the form.
- macro(dfor #* args)¶
dfor
creates a dictionary comprehension. Its syntax is the same as that oflfor
except that it takes two trailing arguments. The first is a form producing the key of each dictionary element, and the second produces the value. Thus:(dfor x (range 5) x (* x 10)) ; => {0 0 1 10 2 20 3 30 4 40}
- macro(gfor #* args)¶
gfor
creates a generator expression. Its syntax is the same as that oflfor
. The difference is thatgfor
returns an iterator, which evaluates and yields values one at a time:(import itertools [count take-while]) (setv accum []) (list (take-while (fn [x] (< x 5)) (gfor x (count) :do (.append accum x) x))) ; => [0 1 2 3 4] accum ; => [0 1 2 3 4 5]
- macro(sfor #* args)¶
sfor
creates a set comprehension.(sfor CLAUSES VALUE)
is equivalent to(set (lfor CLAUSES VALUE))
. Seelfor
.
Context managers and pattern-matching¶
- macro(with managers #* body)¶
with
compiles to awith
or anasync with
statement, which wraps some code with one or more context managers. The first argument is a bracketed list of context managers, and the remaining arguments are body forms.The manager list can't be empty. If it has only one item, that item is evaluated to obtain the context manager to use. If it has two, the first argument (a symbol) is bound to the result of the second. Thus,
(with [(f)] …)
compiles towith f(): …
and(with [x (f)] …)
compiles towith f() as x: …
.(with [o (open "file.txt" "rt")] (print (.read o)))
If the manager list has more than two items, they're understood as variable-manager pairs; thus
(with [v1 e1 v2 e2 v3 e3] ...)
compiles to
with e1 as v1, e2 as v2, e3 as v3: ...
The symbol
_
is interpreted specially as a variable name in the manager list: instead of binding the context manager to the variable_
(as Python'swith e1 as _: …
),with
will leave it anonymous (as Python'swith e1: …
).Finally, any variable-manager pair may be preceded with the keyword
:async
to use an asynchronous context manager:(with [:async v1 e1] …)
with
returns the value of its last form, unless it suppresses an exception (because the context manager's__exit__
method returned true), in which case it returnsNone
. So, the first example could also be written(print (with [o (open "file.txt" "rt")] (.read o)))
- macro(match subject #* cases)¶
match
compiles to a match statement. It requires Python 3.10 or later. The first argument should be the subject, and any remaining arguments should be pairs of patterns and results. Thematch
form returns the value of the corresponding result, orNone
if no case matched.(match (+ 1 1) 1 "one" 2 "two" 3 "three") ; => "two"
You can use
do
to build a complex result form. Patterns, as in Python match statements, are interpreted specially and can't be arbitrary forms. Use(| …)
for OR patterns,PATTERN :as NAME
for AS patterns, and syntax like the usual Hy syntax for literal, capture, value, sequence, mapping, and class patterns. Guards are specified with:if FORM
. Here's a more complex example:(match #(100 200) [100 300] "Case 1" [100 200] :if flag "Case 2" [900 y] f"Case 3, y: {y}" [100 (| 100 200) :as y] f"Case 4, y: {y}" _ "Case 5, I match anything!")
This will match case 2 if
flag
is true and case 4 otherwise.match
can also match against class instances by keyword (or positionally if its__match_args__
attribute is defined; see PEP 636):(import dataclasses [dataclass]) (defclass [dataclass] Point [] #^ int x #^ int y) (match (Point 1 2) (Point 1 x) :if (= (% x 2) 0) x) ; => 2
It's worth emphasizing that
match
is a pattern-matching construct rather than a generic switch construct, and retains all of Python's limitations on match patterns. For example, you can't match against the value of a variable. For more flexible branching constructs, see Hyrule'sbranch
andcase
, or simply usecond
.
Exception-handling¶
- macro(raise exception :from other)¶
raise
compiles to araise
statement, which throws an exception. With no arguments, the current exception is reraised. With one argument, an exception, that exception is raised.(try (raise KeyError) (except [KeyError] (print "gottem")))
raise
supports one other syntax,(raise EXCEPTION_1 :from EXCEPTION_2)
, which compiles toraise EXCEPTION_1 from EXCEPTION_2
.
- macro(try #* body)¶
try
compiles to atry
statement, which can catch exceptions and run cleanup actions. It begins with any number of body forms. Then follows any number ofexcept
orexcept*
(PEP 654) forms, which are expressions that begin with the symbol in question, followed by a list of exception types, followed by more body forms. Finally there are an optionalelse
form and an optionalfinally
form, which again are expressions that begin with the symbol in question and then comprise body forms. Note thatexcept*
requires Python 3.11, andexcept*
andexcept
may not both be used in the sametry
.Here's an example of several of the allowed kinds of child forms:
(try (error-prone-function) (another-error-prone-function) (except [ZeroDivisionError] (print "Division by zero")) (except [[IndexError KeyboardInterrupt]] (print "Index error or Ctrl-C")) (except [e ValueError] (print "ValueError:" (repr e))) (except [e [TabError PermissionError ReferenceError]] (print "Some sort of error:" (repr e))) (else (print "No errors")) (finally (print "All done")))
Exception lists can be in any of several formats:
[]
to catch any subtype ofException
, like Python'sexcept:
[ETYPE]
to catch only the single typeETYPE
, like Python'sexcept ETYPE:
[[ETYPE1 ETYPE2 …]]
to catch any of the named types, like Python'sexcept ETYPE1, ETYPE2, …:
[VAR ETYPE]
to catchETYPE
and bind it toVAR
, like Python'sexcept ETYPE as VAR:
[VAR [ETYPE1 ETYPE2 …]]
to catch any of the named types and bind it toVAR
, like Python'sexcept ETYPE1, ETYPE2, … as VAR:
The return value of
try
is the last form evaluated among the main body,except
forms,except*
forms, andelse
.
Functions¶
- macro(defn name #* args)¶
defn
compiles to a function definition (or possibly to an assignment of a lambda expression). It always returnsNone
. It requires two arguments: a name (given as a symbol; seefn
for anonymous functions) and a "lambda list", or list of parameters (also given as symbols). Any further arguments constitute the body of the function:(defn name [params] bodyform1 bodyform2…)
An empty body is implicitly
(return None)
. If there are at least two body forms, and the first of them is a string literal, this string becomes the docstring of the function. The final body form is implicitly returned; thus,(defn f [] 5)
is equivalent to(defn f [] (return 5))
. There is one exception: due to Python limitations, no implicit return is added if the function is an asynchronous generator (i.e., defined with(defn :async …)
or(fn :async …)
and containing at least oneyield
).defn
accepts a few more optional arguments: a literal keyword:async
(to create a coroutine like Python'sasync def
), a bracketed list of decorators, a list of type parameters (see below), and an annotation (seeannotate
) for the return value. These are placed before the function name (in that order, if several are present):(defn :async [decorator1 decorator2] :tp [T1 T2] #^ annotation name [params] …)
defn
lambda lists support all the same features as Python parameter lists and hence are complex in their full generality. The simplest case is a (possibly empty) list of symbols, indicating that all parameters are required, and can be set by position, as in(f value)
, or by name, as in(f :argument value)
. To set a default value for a parameter, replace the parameter with the bracketed list[pname value]
, wherepname
is the parameter name as a symbol andvalue
is an arbitrary form. Beware that, per Python,value
is evaluated when the function is defined, not when it's called, and if the resulting object is mutated, all calls will see the changes.Further special lambda-list syntax includes:
/
If the symbol
/
is given in place of a parameter, it means that all the preceding parameters can only be set positionally.*
If the symbol
*
is given in place of a parameter, it means that all the following parameters can only be set by name.#* args
If the parameter list contains
#* args
or(unpack-iterable args)
, thenargs
is set to a tuple containing all otherwise unmatched positional arguments. The nameargs
is merely cherished Python tradition; you can use any symbol.#** kwargs
#** kwargs
(a.k.a.(unpack-mapping kwargs)
) is like#* args
, but collects unmatched keyword arguments into a dictionary.
Each of these special constructs is allowed only once, and has the same restrictions as in Python; e.g.,
#* args
must precede#** kwargs
if both are present. Here's an example with a complex lambda list:(defn f [a / b [c 3] * d e #** kwargs] [a b c d e kwargs]) (print (hy.repr (f 1 2 :d 4 :e 5 :f 6))) ; => [1 2 3 4 5 {"f" 6}]
Type parameters require Python 3.12, and have the semantics specified by PEP 695. The keyword
:tp
introduces the list of type parameters. Each item of the list is a symbol, an annotated symbol (such as#^ int T
), or an unpacked symbol (such as#* T
or#** T
). As in Python, unpacking and annotation can't be used with the same parameter.
- macro(fn args)¶
As
defn
, but no name for the new function is required (or allowed), and the newly created function object is returned. Decorators and type parameters aren't allowed, either. However, the function body is understood identically to that ofdefn
, without any of the restrictions of Python'slambda
.:async
is also allowed.
- macro(return object)¶
return
compiles to areturn
statement. It exits the current function, returning its argument if provided with one, orNone
if not.(defn f [x] (for [n (range 10)] (when (> n x) (return n)))) (f 3.9) ; => 4
Note that in Hy,
return
is necessary much less often than in Python. The last form of a function is returned automatically, so an explicitreturn
is only necessary to exit a function early. To get Python's behavior of returningNone
when execution reaches the end of a function, just putNone
there yourself:(defn f [] (setv d (dict :a 1 :b 2)) (.pop d "b") None) (print (f)) ; Prints "None", not "2"
- macro(yield arg1 arg2)¶
yield
compiles to a yield expression, which returns a value as a generator. For a plain yield, provide one argument, the value to yield, or omit it to yieldNone
.(defn naysayer [] (while True (yield "nope"))) (list (zip "abc" (naysayer))) ; => [#("a" "nope") #("b" "nope") #("c" "nope")]
For a yield-from expression, provide two arguments, where the first is the literal keyword
:from
and the second is the subgenerator.(defn myrange [] (setv r (range 10)) (while True (yield :from r))) (list (zip "abc" (myrange))) ; => [#("a" 0) #("b" 1) #("c" 2)]
- macro(await obj)¶
await
creates an await expression. It takes exactly one argument: the object to wait for.(import asyncio) (defn :async main [] (print "hello") (await (asyncio.sleep 1)) (print "world")) (asyncio.run (main))
Macros¶
- macro(defmacro name lambda-list #* body)¶
Define a macro, at both compile-time and run-time. The syntax is a subset allowed of that by
defn
: no decorator or return-type annotations are allowed, and the only types of parameter allowed aresymbol
,[symbol default-value]
,/
, and#* args
. See Macros for details and examples.
- macro(hy.core.macros.defreader _hy-compiler key #* body)¶
Define a reader macro, at both compile-time and run-time. After the name, all arguments are body forms: there is no parameter list as for
defmacro
, since it's up to the reader macro to decide how to parse the source text following its call position. See Reader macros for details and examples.
- macro(hy.core.macros.get-macro _hy-compiler arg1 arg2)¶
Get the function object used to implement a macro. This works for all sorts of macros: core macros, global (i.e., module-level) macros, local macros, and reader macros. For regular (non-reader) macros,
get-macro
is called with one argument, a symbol or string literal, which can be premangled or not according to taste. For reader macros, this argument must be preceded by the literal keyword:reader
(and note that the hash mark,#
, is not included in the name of the reader macro).(get-macro my-macro) (get-macro :reader my-reader-macro)
Except when retrieving a local macro,
get-macro
expands to aget
form on the appropriate object, such as_hy_macros
, selected at the time of expandingget-macro
. This means you can say(del (get-macro …))
, perhaps wrapped ineval-and-compile
oreval-when-compile
, to delete a macro, but it's easy to get confused by the order of evaluation and number of evaluations. For more predictable results in complex situations, use(del (get …))
directly instead of(del (get-macro …))
.
- macro(hy.core.macros.local-macros _hy-compiler)¶
Expands to a dictionary mapping the mangled names of local macros to the function objects used to implement those macros. Thus,
local-macros
provides a rough local equivalent of_hy_macros
.(defn f [] (defmacro m [] "This is the docstring for the macro `m`." 1) (help (get (local-macros) "m"))) (f)
The equivalency is rough in the sense that
local-macros
returns a literal dictionary, not a preexisting object that Hy uses for resolving macro names. So, modifying the dictionary will have no effect.See also
get-macro
.
Classes¶
- macro(defclass arg1 #* args)¶
defclass
compiles to aclass
statement, which creates a new class. It always returnsNone
. Only one argument, specifying the name of the new class as a symbol, is required. A list of decorators (and type parameters, in the same way as fordefn
) may be provided before the class name. After the name comes a list of superclasses (use the empty list[]
for the common case of no superclasses) and any number of body forms, the first of which may be a docstring.A simple class declaration and its uses might look like this:
(defclass MyClass [] "A simple example class." (setv i 12345) (defn f [self] "hello world")) (setv instance (MyClass)) (print instance.i) ; => 12345 (print (.f instance)) ; => hello world
A more complex declaration might look like this:
(defclass [decorator1 decorator2] :tp [T1 T2] MyClass [SuperClass1 SuperClass2] "A class that does things at times." (setv attribute1 value1 attribute2 value2) (defn method1 [self arg1 arg2] …) (defn method2 [self arg1 arg2] …))
Modules¶
- macro(import #* forms)¶
import
compiles to animport
statement, which makes objects in a different module available in the current module. It always returnsNone
. Hy's syntax for the various kinds of import looks like this:;; Import each of these modules. ;; Python: import sys, os.path (import sys os.path) ;; Import several names from a single module. ;; Python: from os.path import exists, isdir as is_dir, isfile (import os.path [exists isdir :as dir? isfile]) ;; Import a module with an alias for the whole module. ;; Python: import sys as systest (import sys :as systest) ;; Import all objects from a module into the current namespace. ;; Python: from sys import * (import sys *) ;; You can list as many imports as you like of different types. ;; Python: ;; from tests.resources import kwtest, function_with_a_dash ;; from os.path import exists, isdir as is_dir, isfile as is_file ;; import sys as systest ;; from math import * (import tests.resources [kwtest function-with-a-dash] os.path [exists isdir :as dir? isfile :as file?] sys :as systest math *)
__all__
can be set to control what's imported by(import module-name *)
, as in Python, but beware that all names in__all__
must be mangled. The macroexport
is a handy way to set__all__
in a Hy program.
- macro(require #* args)¶
require
is a version ofimport
for macros. It allows all the same syntax asimport
, and brings the requested macros into the current scope at compile-time as well as run-time. The following are all equivalent ways to call a macro namedfoo
in the modulemymodule
:(require mymodule) (mymodule.foo 1) (require mymodule :as M) (M.foo 1) (require mymodule [foo]) (foo 1) (require mymodule *) (foo 1) (require mymodule [foo :as bar]) (bar 1)
There's a bit of a trick involved in syntax such as
mymodule.foo
. Namely, there is no object namedmymodule
. Instead,(require mymodule)
assigns every macrofoo
inmymodule
to the name(hy.mangle "mymodule.foo")
in_hy_macros
.Reader macros have a different namespace from regular macros, so they need to be specified with the added syntax
:readers […]
. You could require a reader macro namedspiff
with the call(require mymodule :readers [spiff])
, or star-require reader macros with(require mymodule :readers *)
. For legibility, a regular-macros specification may analogously be prefixed:macros
:(require mymodule :macros [foo] :readers [spiff])
require
with reader macros is more limited than with regular macros. You can't access reader macros with dotted names, and you can't rename them with:as
.Note that
(require mymodule :readers [spiff])
doesn't imply(require mymodule)
; that is,mymodule.foo
won't be made available. If you want that, use something like(require mymodule mymodule :readers [spiff])
To define which macros are collected by
(require mymodule *)
, set the variable_hy_export_macros
(analogous to Python's__all__
) to a list of mangled macro names, which is accomplished most conveniently withexport
. The default behavior is analogous to(import mymodule *)
: all macros are collected other than those whose mangled names begin with an underscore (_
),
- macro(hy.core.macros.export #* args)¶
A convenience macro for defining
__all__
and_hy_export_macros
, which control which Python objects and macros (respectively) are collected by*
imports inimport
andrequire
(respectively).export
allows you to provide the names as symbols instead of strings, and it callshy.mangle
for you on each name.The syntax is
(export objects macros)
, whereobjects
refers to Python objects andmacros
to macros. Keyword arguments are allowed. For example,(export :objects [my-fun MyClass] :macros [my-macro])
exports the function
my-fun
, the classMyClass
, and the macromy-macro
.
Miscellany¶
- macro(chainc #* args)¶
chainc
creates a comparison expression. It isn't required for unchained comparisons, which have only one comparison operator, nor for chains of the same operator. For those cases, you can use the comparison operators directly with Hy's usual prefix syntax, as in(= x 1)
or(< 1 2 3)
. The use ofchainc
is to construct chains of heterogeneous operators, such asx <= y < z
. It uses an infix syntax with the general form(chainc ARG OP ARG OP ARG…)
Hence,
(chainc x <= y < z)
is equivalent to(and (<= x y) (< y z))
, including short-circuiting, except thaty
is only evaluated once.Each
ARG
is an arbitrary form, which does not itself use infix syntax. Usepy
if you want fully Python-style operator syntax. You can also nestchainc
forms, although this is rarely useful. EachOP
is a literal comparison operator; other forms that resolve to a comparison operator are not allowed.At least two
ARG
s and oneOP
are required, and everyOP
must be followed by anARG
.As elsewhere in Hy, the equality operator is spelled
=
, not==
as in Python.
- macro(assert condition [label None])¶
assert
compiles to anassert
statement, which checks whether a condition is true. The first argument, specifying the condition to check, is mandatory, whereas the second, which will be passed toAssertionError
, is optional. The whole form is only evaluated when__debug__
is true, and the second argument is only evaluated when__debug__
is true and the condition fails.assert
always returnsNone
.(assert (= 1 2) "one should equal two") ; AssertionError: one should equal two
Placeholder macros¶
There are a few core macros that are unusual in that all they do, when expanded, is crash, regardless of their arguments:
else
except
except*
finally
unpack-mapping
unquote
unquote-splice
The purpose of these macros is merely to reserve their names. Each
symbol is interpreted specially by one or more other core macros
(e.g., else
in while
) and thus, in these contexts, any
definition of these names as a function or macro would be ignored. If
you really want to, you can override these names like any others, but
beware that, for example, trying to call your new else
inside
while
may not work.
Hy¶
A few core functions, mostly related to the manipulation of Hy code, are
available through the module hy
.
- (hy.read stream filename reader)¶
Like
hy.read-many
, but only one form is read, and shebangs are forbidden. The model corresponding to this specific form is returned, or, if there are no forms left in the stream,EOFError
is raised.stream.pos
is left where it was immediately after the form.
- (hy.read-many stream [filename <string>] reader [skip-shebang False])¶
Parse all the Hy source code in
stream
, which should be a textual file-like object or a string.filename
, if provided, is used in error messages. If noreader
is provided, a newhy.HyReader
object is created. Ifskip_shebang
is true and a shebang line is present, it's detected and discarded first.Return a value of type
hy.models.Lazy
. If you want to evaluate this, be careful to allow evaluating each model before reading the next, as in(hy.eval (hy.read-many o))
. By contrast, forcing all the code to be read before evaluating any of it, as in(hy.eval `(do [~@(hy.read-many o)]))
, will yield the wrong result if one form defines a reader macro that's later used in the same stream to produce new forms.Warning
Thanks to reader macros, reading can execute arbitrary code. Don't read untrusted input.
- (hy.eval model globals locals module macros)¶
An equivalent of Python's
eval()
for evaluating Hy code. The chief difference is that the first argument should be a model rather than source text. If you have a string of source text you want to evaluate, convert it to a model first withhy.read
orhy.read-many
:(hy.eval '(+ 1 1)) ; => 2 (hy.eval (hy.read "(+ 1 1)")) ; => 2
The optional arguments
globals
andlocals
work as in the case ofeval()
.Another optional argument,
module
, can be a module object or a string naming a module. The module's__dict__
attribute can fill in forglobals
(and hence also forlocals
) ifmodule
is provided butglobals
isn't, but the primary purpose ofmodule
is to control where macro calls are looked up. Without this argument, the calling module ofhy.eval
is used instead.(defmacro my-test-mac [] 3) (hy.eval '(my-test-mac)) ; => 3 (import hyrule) (hy.eval '(my-test-mac) :module hyrule) ; NameError (hy.eval '(list-n 3 1) :module hyrule) ; => [1 1 1]
Finally, finer control of macro lookup can be achieved by passing in a dictionary of macros as the
macros
argument. The keys of this dictionary should be mangled macro names, and the values should be function objects to implement those macros. This is the same structure as is produced bylocal-macros
, and in fact,(hy.eval … :macros (local-macros))
is useful to make local macros visible tohy.eval
, which otherwise doesn't see them.(defn f [] (defmacro lmac [] 1) (hy.eval '(lmac)) ; NameError (print (hy.eval '(lmac) :macros (local-macros)))) ; => 1 (f)
In any case, macros provided in this dictionary will shadow macros of the same name that are associated with the provided or implicit module. You can shadow a core macro, too, so be careful: there's no warning for this as there is in the case of
defmacro
.
- (hy.repr obj)¶
This function is Hy's equivalent of Python's
repr()
. It returns a string representing the input object in Hy syntax.(hy.repr [1 2 3]) ; => "[1 2 3]" (repr [1 2 3]) ; => "[1, 2, 3]"
Like
repr
in Python,hy.repr
can round-trip many kinds of values. Round-tripping implies that given an objectx
,(hy.eval (hy.read (hy.repr x)))
returnsx
, or at least a value that's equal tox
. A notable exception to round-tripping is that if a model contains a non-model, the latter will be promoted to a model in the output:(setv x (hy.models.List [5]) output (hy.repr x) y (hy.eval (hy.read output))) (print output) ; '[5] (print (type (get x 0))) ; <class 'int'> (print (type (get y 0))) ; <class 'hy.models.Integer'>
When
hy.repr
doesn't know how to represent an object, it falls back onrepr()
. Usehy.repr-register
to add your own conversion function for a type instead.
- (hy.repr-register types f placeholder)¶
hy.repr-register
lets you set the function thathy.repr
calls to represent a type:(defclass C) (hy.repr-register C (fn [x] "cuddles")) (hy.repr [1 (C) 2]) ; => "[1 cuddles 2]"
Registered functions often call
hy.repr
themselves.hy.repr
will automatically detect self-references, even deeply nested ones, and output"..."
for them instead of calling the usual registered function. To use a placeholder other than"..."
, pass a string of your choice as theplaceholder
argument:(defclass Container) (hy.repr-register Container :placeholder "HY THERE" (fn [x] f"(Container {(hy.repr x.value)})")) (setv container (Container)) (setv container.value container) (hy.repr container) ; => "(Container HY THERE)"
- (hy.mangle s)¶
Stringify the argument (with
str
, notrepr()
orhy.repr
) and convert it to a valid Python identifier according to Hy's mangling rules.(hy.mangle 'foo-bar) ; => "foo_bar" (hy.mangle "🦑") ; => "hyx_XsquidX"
If the stringified argument is already both legal as a Python identifier and normalized according to Unicode normalization form KC (NFKC), it will be returned unchanged. Thus,
hy.mangle
is idempotent.(setv x '♦-->♠) (= (hy.mangle (hy.mangle x)) (hy.mangle x)) ; => True
Generally, the stringifed input is expected to be parsable as a symbol. As a convenience, it can also have the syntax of a dotted identifier, and
hy.mangle
will mangle the dot-delimited parts separately.(hy.mangle "a.c!.d") ; => "a.hyx_cXexclamation_markX.d"
- (hy.unmangle s)¶
Stringify the argument and try to convert it to a pretty unmangled form. See Hy's mangling rules.
(hy.unmangle "hyx_XsquidX") ; => "🦑"
Unmangling may not round-trip, because different Hy symbol names can mangle to the same Python identifier. In particular, Python itself already considers distinct strings that have the same normalized form (according to NFKC), such as
hello
and𝔥𝔢𝔩𝔩𝔬
, to be the same identifier.It's an error to call
hy.unmangle
on something that looks like a properly mangled name but isn't. For example,(hy.unmangle "hyx_XpizzazzX")
is erroneous, because there is no Unicode character named "PIZZAZZ" (yet).
- (hy.macroexpand model module macros)¶
As
hy.macroexpand-1
, but the expansion process is repeated until it has no effect.(defmacro m [x] (and (int x) `(m ~(- x 1)))) (print (hy.repr (hy.macroexpand-1 '(m 5)))) ; => '(m 4) (print (hy.repr (hy.macroexpand '(m 5)))) ; => '0
Note that in general, macro calls in the arguments of the expression still won't expanded. To expand these, too, try Hyrule's
macroexpand-all
.
- (hy.macroexpand-1 model module macros)¶
Check if
model
is anExpression
specifying a macro call. If so, expand the macro and return the expansion; otherwise, returnmodel
unchanged.(defmacro m [x] `(do ~x ~x ~x)) (print (hy.repr (hy.macroexpand-1 '(m (+= n 1))))) ; => '(do (+= n 1) (+= n 1) (+= n 1))
An exceptional case is if the macro is a core macro that returns one of Hy's internal compiler result objects instead of a real model. Then, you just get the original back, as if the macro hadn't been expanded.
The optional arguments
module
andmacros
can be provided to control where macros are looked up, as withhy.eval
.See also
hy.macroexpand
.
- (hy.gensym [g ])¶
Generate a symbol with a unique name. The argument, if provided, will be included in the generated symbol name, as an aid to debugging.
The below example uses the return value of
f
twice but calls it only once, and useshy.gensym
for the temporary variable to avoid collisions with any other variable names.(defmacro selfadd [x] (setv g (hy.gensym)) `(do (setv ~g ~x) (+ ~g ~g))) (defn f [] (print "This is only executed once.") 4) (print (selfadd (f)))
- (hy.as-model x)¶
Convert
x
and any elements thereof into models recursively. This function is called implicitly by Hy in many situations, such as when inserting the expansion of a macro into the surrounding code, so you don't often need to call it. One use is to ensure that models are used on both sides of a comparison:(= 7 '7) ; => False (= (hy.as-model 7) '7) ; => True
It's an error to call
hy.as-model
on an object that contains itself, or an object that isn't representable as a Hy literal, such as a function.
- class (hy.I)¶
hy.I
is an object that provides syntactic sugar for imports. It allows syntax like(hy.I.math.sqrt 2)
to mean(import math) (math.sqrt 2)
, except without bringingmath
ormath.sqrt
into scope. (See hy.R for a version that requires a macro instead of importing a Python object.) This is useful in macros to avoid namespace pollution. To refer to a module with dots in its name, use slashes instead:hy.I.os/path.basename
gets the functionbasename
from the moduleos.path
.You can also call
hy.I
like a function, as in(hy.I "math")
, which is useful when the module name isn't known until run-time. This interface just callsimportlib.import_module()
, avoiding (1) mangling due to attribute lookup, and (2) the translation of/
to.
in the module name. The advantage of(hy.I modname)
overimportlib.import_module(modname)
is merely that it avoids bringingimportlib
itself into scope.
- class (hy.R)¶
There is no actual object named
hy.R
. Rather, this syntax is recognized specially by the compiler as a shorthand for requiring and calling a macro.
Readers¶
Hy's reader (i.e., parser) classes are most interesting to the user in the context of reader macros.
- class hy.HyReader(*, use_current_readers=False)¶
A modular reader for Hy source. It inherits from
hy.Reader
.When
use_current_readers
is true, initialize this reader with all reader macros from the calling module.- fill_pos(model, start)¶
Set position information for
model
.start
should be a (line number, column number) tuple for the start position, whereas the end position is set to the current cursor position.
- parse(stream, filename=None, skip_shebang=False)¶
Yield all models in
stream
. The parameters are understood as inhy.read-many
.
- parse_forms_until(closer)¶
Yield models until the character
closer
is seen. This method is useful for reading sequential constructs such as lists.
- parse_one_form()¶
Parse the next form in the stream and return its model. Any preceding whitespace and comments are skipped over.
- read_default(key)¶
Try to read an identifier. If the next character after that is
"
, then instead parse it as a string with the given prefix (e.g.,r"..."
).(This method is the default reader handler, for when nothing in the read table matches.)
- class hy.Reader¶
An abstract base class for reading input character-by-character.
See
hy.HyReader
for an example of creating a reader class.- reader_table¶
A dictionary mapping a reader-macro key to its dispatch function
- pos¶
A read-only (line, column) tuple indicating the current cursor position of the source being read
- chars(eof_ok=False)¶
Consume and yield characters of the stream. If
eof_ok
is false (the default) and the end of the stream is reached, raisehy.PrematureEndOfInput
.
- dispatch(tag)¶
Call the handler for the reader macro with key
tag
(a string). Return the model it produces, if any.
- end_identifier(character)¶
A context manager to temporarily add a new character to the
ends_ident
set.
- getc()¶
Consume one character from the stream and return it. This method does the bookkeeping for position data, so all character consumption should go through it.
- getn(n)¶
Consume and return
n
characters.
- peek_and_getc(target)¶
Peek at the next character and check if it's equal to
target
, only consuming it if it's equal. Abool
is returned.
- peekc()¶
Peek at the next character, returning it but not consuming it.
- peeking(eof_ok=False)¶
As
chars()
, but without consuming any of the returned characters. This method is useful for looking several characters ahead.
- read_ident(just_peeking=False)¶
Read characters until we hit something in
ends_ident
. The characters are consumed unlessjust_peeking
is true.
- saving_chars()¶
A context manager to save all read characters. The value is a list of characters, rather than a single string.
- slurp_space()¶
Consume and return zero or more whitespace characters.
- exception hy.PrematureEndOfInput(message, expression=None, filename=None, source=None, lineno=1, colno=1)¶
Raised when input ends unexpectedly during parsing.
Python operators¶
Python provides various binary and unary operators. These are usually invoked in Hy using core macros of
the same name: for example, (+ 1 2)
calls the core macro named
+
, which uses Python's addition operator. There are a few exceptions
to the names being the same:
==
in Python is=
in Hy.~
in Python isbnot
in Hy.is not
in Python isis-not
in Hy.not in
in Python isnot-in
in Hy.
For Python's subscription expressions (like x[2]
), Hy has two named
macros, get
and cut
.
By importing from the module hy.pyops
(typically with a star import,
as in (import hy.pyops *)
), you can also use these operators as
functions. Functions are first-class objects, so you can say things like
(map - xs)
to negate all the numbers in the list xs
. Since
macros shadow functions, forms like (- 1 2)
will still call the
macro instead of the function. The functions in hy.pyops
have the
same semantics as their macro equivalents, with one exception: functions
can't short-circuit, so the functions for operators such as and
and
!=
unconditionally evaluate all arguments.
Hy also provides macros for Python's augmented assignment
operators (but no equivalent functions, because Python
semantics don't allow for this). These macros require at least two
arguments even if the parent operator doesn't; for example, (-= x)
is an error even though (- x)
is legal. If the parent operator
supports more than two arguments, though, so does the
augmented-assignment version, using an aggregation operator to bind up
all arguments past the first into a single rvalue. Typically, the
aggregator is the same as the original operator: for example, (+=
count n1 n2 n3)
is equivalent to (+= count (+ n1 n2 n3))
.
Exceptions (such as -=
, which uses the aggregator +
, so (-= count n1 n2 n3)
is equivalent to (-= count
(+ n1 n2 n3))
) are noted in the documentation for the parent operator
(such as -
for -=
).
- (hy.pyops.!= a1 a2 #* a-rest)¶
The inequality operator. Its effect can be defined by the equivalent Python:
(!= x y)
→x != y
(!= a1 a2 … an)
→a1 != a2 != … != an
- (hy.pyops.% x y)¶
The modulus operator. Its effect can be defined by the equivalent Python:
(% x y)
→x % y
- (hy.pyops.& a1 #* a-rest)¶
The bitwise AND operator. Its effect can be defined by the equivalent Python:
(& x)
→x
(& x y)
→x & y
(& a1 a2 … an)
→a1 & a2 & … & an
- (hy.pyops.* #* args)¶
The multiplication operator. Its effect can be defined by the equivalent Python:
(*)
→1
(* x)
→x
(* x y)
→x * y
(* a1 a2 … an)
→a1 * a2 * … * an
- (hy.pyops.** a1 a2 #* a-rest)¶
The exponentiation operator. Its effect can be defined by the equivalent Python:
(** x y)
→x ** y
(** a1 a2 … an)
→a1 ** a2 ** … ** an
- (hy.pyops.+ #* args)¶
The addition operator. Its effect can be defined by the equivalent Python:
(+)
→0
(+ x)
→+x
(+ x y)
→x + y
(+ a1 a2 … an)
→a1 + a2 + … + an
- (hy.pyops.- a1 #* a-rest)¶
The subtraction operator. Its effect can be defined by the equivalent Python:
(- x)
→-x
(- x y)
→x - y
(- a1 a2 … an)
→a1 - a2 - … - an
Aggregator for augmented assignment:
+
- (hy.pyops./ a1 #* a-rest)¶
The division operator. Its effect can be defined by the equivalent Python:
(/ x)
→1 / x
(/ x y)
→x / y
(/ a1 a2 … an)
→a1 / a2 / … / an
Aggregator for augmented assignment:
*
- (hy.pyops.// a1 a2 #* a-rest)¶
The floor division operator. Its effect can be defined by the equivalent Python:
(// x y)
→x // y
(// a1 a2 … an)
→a1 // a2 // … // an
- (hy.pyops.< a1 #* a-rest)¶
The less-than operator. Its effect can be defined by the equivalent Python:
(< x)
→True
(< x y)
→x < y
(< a1 a2 … an)
→a1 < a2 < … < an
- (hy.pyops.<< a1 a2 #* a-rest)¶
The left shift operator. Its effect can be defined by the equivalent Python:
(<< x y)
→x << y
(<< a1 a2 … an)
→a1 << a2 << … << an
Aggregator for augmented assignment:
+
- (hy.pyops.<= a1 #* a-rest)¶
The less-than-or-equal-to operator. Its effect can be defined by the equivalent Python:
(<= x)
→True
(<= x y)
→x <= y
(<= a1 a2 … an)
→a1 <= a2 <= … <= an
- (hy.pyops.= a1 #* a-rest)¶
The equality operator. Its effect can be defined by the equivalent Python:
(= x)
→True
(= x y)
→x == y
(= a1 a2 … an)
→a1 == a2 == … == an
- (hy.pyops.> a1 #* a-rest)¶
The greater-than operator. Its effect can be defined by the equivalent Python:
(> x)
→True
(> x y)
→x > y
(> a1 a2 … an)
→a1 > a2 > … > an
- (hy.pyops.>= a1 #* a-rest)¶
The greater-than-or-equal-to operator. Its effect can be defined by the equivalent Python:
(>= x)
→True
(>= x y)
→x >= y
(>= a1 a2 … an)
→a1 >= a2 >= … >= an
- (hy.pyops.>> a1 a2 #* a-rest)¶
The right shift operator. Its effect can be defined by the equivalent Python:
(>> x y)
→x >> y
(>> a1 a2 … an)
→a1 >> a2 >> … >> an
Aggregator for augmented assignment:
+
- (hy.pyops.@ a1 #* a-rest)¶
The matrix multiplication operator. Its effect can be defined by the equivalent Python:
(@ x y)
→x @ y
(@ a1 a2 … an)
→a1 @ a2 @ … @ an
- (hy.pyops.^ x y)¶
The bitwise XOR operator. Its effect can be defined by the equivalent Python:
(^ x y)
→x ^ y
- (hy.pyops.and #* args)¶
The logical conjuction operator. Its effect can be defined by the equivalent Python:
(and)
→True
(and x)
→x
(and x y)
→x and y
(and a1 a2 … an)
→a1 and a2 and … and an
- (hy.pyops.bnot x)¶
The bitwise NOT operator. Its effect can be defined by the equivalent Python:
(bnot x)
→~x
- (hy.pyops.cut coll [arg1 sentinel] [arg2 sentinel] [arg3 sentinel])¶
cut
compiles to a slicing expression, which selects multiple elements of a sequential data structure. The first argument is the object to be sliced. The remaining arguments are optional, and understood the same way as in a Python slicing expression.(setv x "abcdef") (cut x) ; => "abcdef" (cut x 2) ; => "ab" (cut x 2 None) ; => "cdef" (cut x 3 5) ; => "de" (cut x -3 None) ; => "def" (cut x 0 None 2) ; => "ace"
A call to the
cut
macro (but not its function version inhy.pyops
) is a valid target for assignment (withsetv
,+=
, etc.) and for deletion (withdel
).
- (hy.pyops.get coll key1 #* keys)¶
get
compiles to one or more subscription expressions, which select an element of a data structure. The first two arguments are the collection object and a key; for example,(get person name)
compiles toperson[name]
. Subsequent arguments indicate chained subscripts, so(get person name "surname" 0)
becomesperson[name]["surname"][0]
. You can assign to aget
form, as in(setv real-estate {"price" 1,500,000}) (setv (get real-estate "price") 0)
but this doesn't work with the function version of
get
fromhy.pyops
, due to Python limitations on lvalues.If you're looking for the Hy equivalent of Python list slicing, as in
foo[1:3]
, note that this is just Python's syntactic sugar forfoo[slice(1, 3)]
, and Hy provides its own syntactic sugar for this with a different macro,cut
.
- (hy.pyops.in a1 a2 #* a-rest)¶
The membership test operator. Its effect can be defined by the equivalent Python:
(in x y)
→x in y
(in a1 a2 … an)
→a1 in a2 in … in an
- (hy.pyops.is a1 #* a-rest)¶
The identicality test operator. Its effect can be defined by the equivalent Python:
(is x)
→True
(is x y)
→x is y
(is a1 a2 … an)
→a1 is a2 is … is an
- (hy.pyops.is-not a1 a2 #* a-rest)¶
The negated identicality test operator. Its effect can be defined by the equivalent Python:
(is-not x y)
→x is not y
(is-not a1 a2 … an)
→a1 is not a2 is not … is not an
- (hy.pyops.not-in a1 a2 #* a-rest)¶
The negated membership test operator. Its effect can be defined by the equivalent Python:
(not-in x y)
→x not in y
(not-in a1 a2 … an)
→a1 not in a2 not in … not in an
- (hy.pyops.or #* args)¶
The logical disjunction operator. Its effect can be defined by the equivalent Python:
(or)
→None
(or x)
→x
(or x y)
→x or y
(or a1 a2 … an)
→a1 or a2 or … or an
- (hy.pyops.| #* args)¶
The bitwise OR operator. Its effect can be defined by the equivalent Python:
(|)
→0
(| x)
→x
(| x y)
→x | y
(| a1 a2 … an)
→a1 | a2 | … | an