Hy (github) is a Lisp variant embedded in CPython. The syntax is is mostly homoiconic, using a Clojure-like reader. Hy is converted to Python's AST and then compiled to Python bytecode. It is tested with Python 2.7 and 3.{4-7}.
Hy is changing rapidly. hy/NEWS.rst has information about the latest changes; this often has not yet filtered into the documentation in the docs dir of the repo.
Other Python Lisp projects:
- Pixie on RPython, with a JIT compiler. 8 commits in 2017. Author interview.
- clojure-py, an implementation of Clojure in pure Python. Defunct since 2012.
pip install hy
pip install git+https://github.com/hylang/hy.git
Also see the Documentation Index.
- Hyphens are replaced with underbars:
foo-bar
→foo_bar
- Earmuffed names are converted to upper case:
*foo*
→FOO
- UTF-8 names are encoded with punycode and prefixed with
hy_
:i♥u
→hy_iu_t0x
Syntax:
- '#!': Ignored when first line of script.
;
: Comment."..."
: Strings must always use double quotes.
Hy expressions when printed by the standard Python repr
make '(7, "abc")
appear as HyExpression([HyInteger(7), HyString('abc')])
. The
hy.contrib.hy-repr
module has a hy-repr
function to print in
standard Hy format instead, and this can be used in the REPL:
$ hy --repl-output-fn=hy.contrib.hy-repr.hy-repr
=> '(7 "abc")
'(7 "abc")
hy-repr
will call an object's __hy-repr__()
method if available,
and will fall back to standard Python repr
when it doesn't know how
to handle a format.
Like Python repr
, where possible hy-repr
output should be
invertable with (eval (read-str (hy-repr x)))
returning x or an
object equal to it.
For more detailed information, see Hy (the language).
None
,True
,False
: Equivalant ofnil
,true
,false
in other Lisps.- Numbers may be preceeded by
0x
/0o
/0b
for base 16/8/2. Underscores and commas may appear anywhere in a numeric literal except at the start:(+ 10,000 20_000))
=> 30000.NaN
,Inf
and-Inf
are available. n/m
: PythonFraction(n, m)
"..."
: String with\
escapes and literal newlines allowed. (Single quotes, triple quotes not available.) Prefix withr
for raw (no escapes),b
for bytes. Strings are always Unicode; under Python 2"foo"
→u"foo"
andb"foo"
→"foo"
.#[delim[...]delim]
: Raw bracket string; delim may be any string not containing[
/]
, including empty:#[[Say "hi."]]
. An initial newline is removed; all others are literal.'
: Prefixed to a form, prevents evaluation. E.g.:'name
is literal name,'()
is literal empty list.()
:HyExpression
.[]
:HyList
.{}
: Pythondict
. E.g.,{"a" 1 2 2.0 :foo None}
⇒{2: 2.0, '\ufdd0:foo': None, 'a': 1}
#{}
: Python set, E.g.,#{"one" 2 :three}
:name
: Keyword. Evaluates to'\ufdd0:foo'
except when used as literal in a function call indicating keyword argument. Can be quoted:(f ':foo)
→f('\ufdd0:foo')
.#_
: Discard prefix; following form is discarded instead of compiled. Useful for commenting out forms.(list-comp expr selector filter)
: List comprehension: evaluate expr form for every value generated by selector form where optional filter form is true. Seelist-comp
.
See Built-Ins for more details.
(setv x form [y form2 ...])
: Bind result of form to x.(defn f [arg ...] (form))
: Define a function.(defclass C [parent ...] [...])
: Class definition(do form ...)
: A "block" of multiple forms (used with if, cond, etc.), as with progn in other Lisps.(if pform tform fform)
: pform is a predicate; tform and fform default toTrue
andFalse
.(cond [pform tform] ...)
: Conditional: first matching pform evaluates its tform and then evaulation stops. Use[True tform]
at end for default match.(with [name cform]] form)
: Context manager binding cform to name:(with [f (open "/foo")] (print (.read f)))
.(import ...)
: Import. Uses unquoted names,(import os)
.
Functions (and macros) are called by putting them as the first element
of a form, followed by the arguments: (+ 1 2)
. Prefixing a function
name with a .
calls the method on the succeeding object:
(.startswith "abc" "a")
⇒ True
. You can also call in standard
obj.method format with names (but not literals):
(setv s "abc")
(s.startswith "a") ; ⇒ True, just like (s.startswith s "a")
("abc".startswith "a") ; HyTypeError: cannot access attribute
; on anything other than a name
Generally, Python functions are directly available in Hy under the
same name. Dyadic functions are extended to more than two arguments
where appropriate, e.g., (+ "a" "b" "c")
.
See Built-Ins and Hy Core for more details on built-in functions.