Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Documentation improvements #2533

Merged
merged 2 commits into from
Nov 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 20 additions & 10 deletions docs/macros.rst
Original file line number Diff line number Diff line change
Expand Up @@ -156,22 +156,32 @@ Ultimately it's wisest to use only four kinds of names in macro expansions: gens
Reader macros
-------------

Reader macros allow you to hook directly into Hy's parser to customize how text is parsed into models. They're defined with :hy:func:`defreader`, or, like regular macros, brought in from other modules with :hy:func:`require`. Rather than receiving function arguments, a reader macro has access to a :py:class:`HyReader <hy.reader.hy_reader.HyReader>` object named ``&reader``, which provides all the text-parsing logic that Hy uses to parse itself (see :py:class:`HyReader <hy.reader.hy_reader.HyReader>` and its base class :py:class:`Reader <hy.reader.reader.Reader>` for the available methods). A reader macro is called with the hash sign ``#``, and like a regular macro, it should return a model or something convertible to a model. ::
Reader macros allow you to hook directly into Hy's parser to customize how text is parsed into models. They're defined with :hy:func:`defreader`, or, like regular macros, brought in from other modules with :hy:func:`require`. Rather than receiving function arguments, a reader macro has access to a :py:class:`HyReader <hy.reader.hy_reader.HyReader>` object named ``&reader``, which provides all the text-parsing logic that Hy uses to parse itself (see :py:class:`HyReader <hy.reader.hy_reader.HyReader>` and its base class :py:class:`Reader <hy.reader.reader.Reader>` for the available methods). A reader macro is called with the hash sign ``#``, and like a regular macro, it should return a model or something convertible to a model.

Here's a moderately complex example of a reader macro that couldn't be implemented as a regular macro. It reads in a list of lists in which the inner lists are newline-separated, but newlines are allowed inside elements. ::

(defreader matrix
(.slurp-space &reader)
(setv start (.getc &reader))
(assert (= start "["))
(.slurp-space &reader)
(setv out [[]])
(while (not (do (.slurp-space &reader) (.peek-and-getc &reader "]")))
(setv x (.parse-one-form &reader))
(if (= x '|)
(.append out [])
(.append (get out -1) x)))
(if (= out [[]]) [] out))

(print (hy.repr #matrix [1 2 3 | 4 5 6 | 7 8 9]))
; => [[1 2 3] [4 5 6] [7 8 9]]
(while (not (.peek-and-getc &reader "]"))
(cond
(any (gfor c " \t" (.peek-and-getc &reader c)))
None
(.peek-and-getc &reader "\n")
(.append out [])
True
(.append (get out -1) (.parse-one-form &reader))))
(lfor line out :if line line))

(print (hy.repr #matrix [
1 (+ 1 1) 3
4 ["element" "containing"
"a" "newline"] 6
7 8 9]))
; => [[1 2 3] [4 ["element" "containing" "a" "newline"] 6] [7 8 9]]

Note that because reader macros are evaluated at parse-time, and top-level forms are completely parsed before any further compile-time execution occurs, you can't use a reader macro in the same top-level form that defines it::

Expand Down
22 changes: 17 additions & 5 deletions docs/whyhy.rst
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,20 @@ aforementioned mixing of statements and expressions, :ref:`name mangling
Python-legal identifiers, and a :hy:func:`let` macro to provide block-level scoping
in place of Python's usual function-level scoping.

Overall, Hy, like Common Lisp, is intended to be an unopinionated big-tent
language that lets you do what you want. If you're interested in a more
small-and-beautiful approach to Lisp, in the style of Scheme, check out
`Hissp <https://github.com/gilch/hissp>`_, another Lisp embedded in Python
that was created by a Hy developer.

What Hy is not
--------------

Hy isn't minimal or elegant. Hy is big and ugly and proud of it; it's an
unopinionated big-tent language that lets you do what you want. It has all
of Python's least-motivated semantic features, plus more features, plus
various kinds of syntactic sugar. (The syntax isn't as complex as
Python's, but there are a lot of details beyond plain old S-expressions.)
If you're interested in a more small-and-beautiful approach to Lisp, in
the style of Scheme, check out `Hissp <https://github.com/gilch/hissp>`_,
another Lisp embedded in Python that was created by a Hy developer.

Also, Hy isn't a reimplementation of an older Lisp. It is its own
language. It looks kind of like Clojure and kind of like Common Lisp, but
nontrivial programs that run in one of these langauges can't be expected
to run on another unaltered.