Skip to content

Commit

Permalink
Lots of small improvements to the manual
Browse files Browse the repository at this point in the history
  • Loading branch information
Kodiologist committed Oct 2, 2023
1 parent 902233d commit a8d4311
Show file tree
Hide file tree
Showing 9 changed files with 70 additions and 65 deletions.
8 changes: 4 additions & 4 deletions docs/cli.rst
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ for a complete list of options and :py:ref:`Python's documentation
.. cmdoption:: --repl-output-fn

Set the :ref:`REPL output function <repl-output-function>`. This can be the
name of a Python builtin, mostly likely ``repr``, or a dotted name like
name of a Python builtin, most likely ``repr``, or a dotted name like
``foo.bar.baz``. In the latter case, Hy will attempt to import the named
object with code like ``(import foo.bar [baz])``.

Expand All @@ -45,10 +45,10 @@ for a complete list of options and :py:ref:`Python's documentation
hy2py
-----

``hy2py`` is a program to convert Hy source code into Python source code. Use ``hy2py --help`` for usage instructions. It can take its input from standard input, or from a file or module name provided as a command-line argument. In the case of a module name, the current working directory should be the parent directory of that module, and the output parameter (``--output/-o``) is required. When the output parameter is provided, the output will be written into the folder or file. Otherwise, the result is written to standard output.
``hy2py`` is a program to convert Hy source code into Python source code. Use ``hy2py --help`` for usage instructions. It can take its input from standard input, or from a file or module name provided as a command-line argument. In the case of a module name, the current working directory should be the parent directory of that module, and the output parameter (``--output/-o``) is required. When the output parameter is provided, the output will be written into the given folder or file. Otherwise, the result is written to standard output.

.. warning::
``hy2py`` can execute arbitrary code. Don't give it untrusted input.
``hy2py`` can execute arbitrary code (via macros, :hy:func:`eval-when-compile`, etc.). Don't give it untrusted input.



Expand All @@ -60,4 +60,4 @@ hyc
``hyc`` is a program to compile files of Hy code into Python bytecode. Use ``hyc --help`` for usage instructions. The generated bytecode files are named and placed according to the usual scheme of your Python executable, as indicated by :py:func:`importlib.util.cache_from_source`.

.. warning::
``hyc`` can execute arbitrary code. Don't give it untrusted input.
``hyc`` can execute arbitrary code (via macros, :hy:func:`eval-when-compile`, etc.). Don't give it untrusted input.
3 changes: 2 additions & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ Hy is a Lisp dialect that's embedded in Python. Since Hy transforms its Lisp
code into Python abstract syntax tree (AST) objects, you have the whole
beautiful world of Python at your fingertips, in Lisp form.

.. Changes to this paragraph should be mirrored on Hy's homepage.
.. Changes to the below paragraph should be mirrored on Hy's homepage
and the README.
To install the latest release of Hy, just use the command ``pip3 install
--user hy``. Then you can start an interactive read-eval-print loop (REPL) with
Expand Down
15 changes: 5 additions & 10 deletions docs/interop.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,17 @@
Python Interoperability
=======================

Despite being a Lisp, Hy aims to be fully compatible with Python. That means
every Python module or package can be imported in Hy code, and vice versa.

:ref:`Mangling <mangling>` allows variable names to be spelled differently in
Hy and Python. For example, Python's ``str.format_map`` can be written
``str.format-map`` in Hy, and a Hy function named ``valid?`` would be called
``is_valid`` in Python. You can call :hy:func:`hy.mangle` and
``hyx_valid_Xquestion_markX`` in Python. You can call :hy:func:`hy.mangle` and
:hy:func:`hy.unmangle` from either language.

Using Python from Hy
====================

To use a Python module from Hy, just :hy:func:`import` it. No additional
ceremony is required.
To use a Python module from Hy, just :hy:func:`import` it. In most cases, no
additional ceremony is required.

You can embed Python code directly into a Hy program with the macros
:hy:func:`py <py>` and :hy:func:`pys <pys>`, and you can use standard Python
Expand All @@ -43,7 +40,7 @@ still import ``hy``, and thus require Hy to be installed in order to run; see
:ref:`implicit-names` for details and workarounds.

To execute Hy code from a string, use :hy:func:`hy.read-many` to convert it to
:ref:`models <models>` and then :hy:func:`hy.eval` to evaluate it:
:ref:`models <models>` and :hy:func:`hy.eval` to evaluate it:

.. code-block:: python
Expand All @@ -59,9 +56,7 @@ You can use :meth:`hy.REPL.run` to launch the Hy REPL from Python, as in
Libraries that expect Python
============================

There are various means by which Hy may interact poorly with a Python library

because the library doesn't account for the possibility of Hy. For example,
There are various means by which Hy may interact poorly with a Python library because the library doesn't account for the possibility of Hy. For example,
when you run :ref:`hy-cli`, ``sys.executable`` will be set to
this program rather than the original Python binary. This is helpful more often
than not, but will lead to trouble if e.g. the library tries to call
Expand Down
2 changes: 1 addition & 1 deletion docs/repl.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Output functions
By default, the return value of each REPL input is printed with
:hy:func:`hy.repr`. To change this, you can set the REPL output function with
e.g. the command-line argument ``--repl-output-fn``. Use :func:`repr` to get
Python representations like Python's own REPL.
Python representations, like Python's own REPL.

Regardless of the output function, no output is produced when the value is
``None``, as in Python.
Expand Down
4 changes: 2 additions & 2 deletions docs/semantics.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,10 @@ called first, call it before ``f``.
When bytecode is regenerated
----------------------------

The first time Hy is asked to execute a file, it will produce a bytecode file
The first time Hy is asked to execute a file, whether directly or indirectly (as in the case of an import), it will produce a bytecode file
(unless :std:envvar:`PYTHONDONTWRITEBYTECODE` is set). Subsequently, if the
source file hasn't changed, Hy will load the bytecode instead of recompiling
the source. Python behaves similarly, but the difference between recompilation
the source. Python also makes bytecode files, but the difference between recompilation
and loading bytecode is more consequential in Hy because of how Hy lets you run
and generate code at compile-time with things like macros, reader macros, and
:hy:func:`eval-and-compile`. You may be surprised by behavior like the
Expand Down
38 changes: 16 additions & 22 deletions docs/syntax.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ somewhat different (such as :class:`Set <hy.models.Set>`, which is ordered,
unlike actual :class:`set`\s). All models inherit from :class:`Object
<hy.models.Object>`, which stores textual position information, so tracebacks
can point to the right place in the code. The compiler takes whatever models
are left over after parsing and macro expansion and translates them into Python
are left over after parsing and macro-expansion and translates them into Python
:mod:`ast` nodes (e.g., :class:`Integer <hy.models.Integer>` becomes
:class:`ast.Constant`), which can then be evaluated or rendered as Python code.
Macros (that is, regular macros, as opposed to reader macros) operate on the
model level, taking some models as arguments and returning more models for
compilation or further macro expansion; they're free to do quite different
compilation or further macro-expansion; they're free to do quite different
things with a given model than the compiler does, if it pleases them to, like
using an :class:`Integer <hy.models.Integer>` to construct a :class:`Symbol
<hy.models.Symbol>`.
Expand Down Expand Up @@ -177,8 +177,8 @@ Literal keywords are most often used for their special treatment in
as values. For example, ``(f :foo 3)`` calls the function ``f`` with the
parameter ``foo`` set to ``3``. The keyword is also :ref:`mangled <mangling>`
at compile-time. To prevent a literal keyword from being treated specially in
an expression, you can :hy:func:`quote` the keyword, or you can use it itself
as a keyword argument, as in ``(f :foo :bar)``.
an expression, you can :hy:func:`quote` the keyword, or you can use it as the
value for another keyword argument, as in ``(f :foo :bar)``.

Otherwise, keywords are simple model objects that evaluate to themselves. Users
of other Lisps should note that it's often a better idea to use a string than a
Expand Down Expand Up @@ -312,7 +312,7 @@ Hy allows double-quoted strings (e.g., ``"hello"``), but not single-quoted
strings like Python. The single-quote character ``'`` is reserved for
preventing the evaluation of a form, (e.g., ``'(+ 1 1)``), as in most Lisps
(see :ref:`more-sugar`). Python's so-called triple-quoted strings (e.g.,
``'''hello'''`` and ``"""hello"""``) aren't supported. However, in Hy, unlike
``'''hello'''`` and ``"""hello"""``) aren't supported, either. However, in Hy, unlike
Python, any string literal can contain newlines; furthermore, Hy has
:ref:`bracket strings <bracket-strings>`. For consistency with Python's
triple-quoted strings, all literal newlines in literal strings are read as in
Expand All @@ -324,8 +324,8 @@ Unrecognized escape sequences are a syntax error. To create a "raw string" that
interprets all backslashes literally, prefix the string with ``r``, as in
``r"slash\not"``.

Like Python, Hy treats all string literals as sequences of Unicode characters
by default. The result is the model type :class:`String <hy.models.String>`.
By default, all string literals are regarded as sequences of Unicode characters.
The result is the model type :class:`String <hy.models.String>`.
You may prefix a string literal with ``b`` to treat it as a sequence of bytes,
producing :class:`Bytes <hy.models.Bytes>` instead.

Expand All @@ -351,10 +351,10 @@ like the here-documents of other languages. A bracket string begins with
begins with ``f-``, the bracket string is interpreted as an :ref:`f-string
<syntax-fstrings>`.) For example::

=> (print #[["That's very kind of yuo [sic]" Tom wrote back.]])
"That's very kind of yuo [sic]" Tom wrote back.
=> (print #[==[1 + 1 = 2]==])
1 + 1 = 2
(print #[["That's very kind of yuo [sic]" Tom wrote back.]])
; "That's very kind of yuo [sic]" Tom wrote back.
(print #[==[1 + 1 = 2]==])
; 1 + 1 = 2

Bracket strings are always raw Unicode strings, and don't allow the ``r`` or
``b`` prefixes.
Expand Down Expand Up @@ -451,25 +451,19 @@ A format string (or "f-string", or "formatted string literal") is a string
literal with embedded code, possibly accompanied by formatting commands. The
result is an :class:`FString <hy.models.FString>`, Hy f-strings work much like
:ref:`Python f-strings <py:f-strings>` except that the embedded code is in Hy
rather than Python.
rather than Python. ::

::

=> (print f"The sum is {(+ 1 1)}.")
The sum is 2.
(print f"The sum is {(+ 1 1)}.") ; => The sum is 2.

Since ``=``, ``!``, and ``:`` are identifier characters in Hy, Hy decides where
the code in a replacement field ends (and any debugging ``=``, conversion
specifier, or format specifier begins) by parsing exactly one form. You can use
``do`` to combine several forms into one, as usual. Whitespace may be necessary
to terminate the form::

=> (setv foo "a")
=> (print f"{foo:x<5}")
NameError: name 'hyx_fooXcolonXxXlessHthan_signX5' is not defined
=> (print f"{foo :x<5}")
axxxx
(setv foo "a")
(print f"{foo:x<5}") ; => NameError: name 'hyx_fooXcolonXxXlessHthan_signX5' is not defined
(print f"{foo :x<5}") ; => axxxx

Unlike Python, whitespace is allowed between a conversion and a format
specifier.
Expand Down
22 changes: 14 additions & 8 deletions docs/tutorial.rst
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,13 @@ the **form**. ``92``, ``*``, and ``(* 92 2)`` are all forms. A Lisp program
consists of a sequence of forms nested within forms. Forms are typically
separated from each other by whitespace, but some forms, such as string
literals (``"Hy, world!"``), can contain whitespace themselves. An
**expression** is a form enclosed in parentheses; its first child form, called
the **head**, determines what the expression does, and should generally be a
function or macro. Functions are the most ordinary sort of head, whereas macros
(described in more detail below) are functions executed at compile-time instead
and return code to be executed at run-time.
:ref:`expression <expressions>` is a form enclosed in parentheses; its first
child form, called the **head**, determines what the expression does, and
should generally be a function or macro. :py:term:`Functions <function>`, the
most ordinary sort of head, constitute reusable pieces of code that can take in
arguments and return a value. Macros (described in more detail :ref:`below
<tutorial-macros>`) are a special kind of function that's executed at
compile-time and returns code to be executed at run-time.

Comments start with a ``;`` character and continue till the end of the line. A
comment is functionally equivalent to whitespace. ::
Expand Down Expand Up @@ -260,6 +262,8 @@ Python can import a Hy module like any other module so long as Hy itself has
been imported first, which, of course, must have already happened if you're
running a Hy program.

.. _tutorial-macros:

Macros
======

Expand All @@ -277,7 +281,9 @@ program. Here's a simple example::
(print "Value:" (m))
(print "Done executing")

If you run this program twice in a row, you'll see this::
If you run this program twice in a row, you'll see this:

.. code-block:: text
$ hy example.hy
Now for a slow computation
Expand All @@ -300,8 +306,8 @@ simply::
(print "Value:" 1)
(print "Done executing")

Our macro ``m`` has an especially simple return value, an integer, which at
compile-time is converted to an integer literal. In general, macros can return
Our macro ``m`` has an especially simple return value, an integer (:py:class:`int`), which at
compile-time is converted to an integer model (:class:`hy.models.Integer`). In general, macros can return
arbitrary Hy forms to be executed as code. There are several helper macros that
make it easy to construct forms programmatically, such as :hy:func:`quote`
(``'``), :hy:func:`quasiquote` (`````), :hy:func:`unquote` (``~``),
Expand Down
41 changes: 25 additions & 16 deletions docs/whyhy.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Why Hy?
=======

.. Changes to this paragraph should be mirrored on Hy's homepage.
.. Changes to the below paragraph should be mirrored on Hy's homepage.
Hy (or "Hylang" for long; named after the insect order Hymenoptera,
since Paul Tagliamonte was studying swarm behavior when he created the
Expand All @@ -22,19 +22,27 @@ Hy versus Python

The first thing a Python programmer will notice about Hy is that it has Lisp's
traditional parenthesis-heavy prefix syntax in place of Python's C-like infix
syntax. For example, ``print("The answer is", 2 + object.method(arg))`` could
be written ``(print "The answer is" (+ 2 (.method object arg)))`` in Hy.
Consequently, Hy is free-form: structure is indicated by punctuation rather
syntax. For example,

.. code-block:: python
print("The answer is", 2 + object.method(arg))
could be written ::

(print "The answer is" (+ 2 (.method object arg)))

in Hy. Consequently, Hy is free-form: structure is indicated by punctuation rather
than whitespace, making it convenient for command-line use.

As in other Lisps, the value of a simplistic syntax is that it facilitates
Lisp's signature feature: `metaprogramming
<https://en.wikipedia.org/wiki/Metaprogramming>`_ through macros, which are
functions that manipulate code objects at compile time to produce new code
objects, which are then executed as if they had been part of the original code.
In fact, Hy allows arbitrary computation at compile-time. For example, here's a
simple macro that implements a C-style do-while loop, which executes its body
for as long as the condition is true, but at least once.
<https://en.wikipedia.org/wiki/Metaprogramming>`_ through :doc:`macros
<macros>`, which are functions that manipulate code objects at compile time to
produce new code objects, which are then executed as if they had been part of
the original code. In fact, Hy allows arbitrary computation at compile-time. For
example, here's a simple macro that implements a C-style do-while loop, which
executes its body for as long as the condition is true, but at least once.

.. _do-while:

Expand All @@ -52,7 +60,7 @@ for as long as the condition is true, but at least once.

Hy also removes Python's restrictions on mixing expressions and statements,
allowing for more direct and functional code. For example, Python doesn't allow
:ref:`with <py:with>` blocks, which close a resource once you're done using it,
:keyword:`with` blocks, which close a resource once you're done using it,
to return values. They can only execute a set of statements:

.. code-block:: python
Expand All @@ -70,7 +78,7 @@ it like an ordinary function call::
(len (with [o (open "foo")] (.read o)))
(len (with [o (open "bar")] (.read o)))))

To be even more concise, you can put a ``with`` form in a :hy:func:`gfor <gfor>`::
To be even more concise, you can put a ``with`` form in a :hy:func:`gfor`::

(print (sum (gfor
filename ["foo" "bar"]
Expand All @@ -81,9 +89,9 @@ Operators can be given more than two arguments (e.g., ``(+ 1 2 3)``), including
augmented assignment operators (e.g., ``(+= x 1 2 3)``). They are also provided
as ordinary first-class functions of the same name, allowing them to be passed
to higher-order functions: ``(sum xs)`` could be written ``(reduce + xs)``,
after importing the function ``+`` from the module ``hy.pyops``.
after importing the function ``+`` from the module :hy:mod:`hy.pyops`.

The Hy compiler works by reading Hy source code into Hy model objects and
The Hy compiler works by reading Hy source code into Hy :ref:`model objects <models>` and
compiling the Hy model objects into Python abstract syntax tree (:py:mod:`ast`)
objects. Python AST objects can then be compiled and run by Python itself,
byte-compiled for faster execution later, or rendered into Python source code.
Expand Down Expand Up @@ -131,8 +139,9 @@ in a set literal. However, models can be concatenated and indexed just like
plain lists, and you can return ordinary Python types from a macro or give them
to :hy:func:`hy.eval` and Hy will automatically promote them to models.

Hy takes much of its semantics from Python. For example, Hy is a Lisp-1 because
Python functions use the same namespace as objects that aren't functions. In
Hy takes much of its semantics from Python. For example, functions use the same
namespace as objects that aren't functions, so a variable named ``globals``
can shadow the Python built-in function :py:func:`globals`. In
general, any Python code should be possible to literally translate to Hy. At
the same time, Hy goes to some lengths to allow you to do typical Lisp things
that aren't straightforward in Python. For example, Hy provides the
Expand Down
2 changes: 1 addition & 1 deletion hy/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -537,7 +537,7 @@ class Dict(Sequence):
Represents a literal :class:`dict`. ``keys``, ``values``, and ``items`` methods are
provided, each returning a list, although this model type does none of the
normalization of a real :class:`dict`. In the case of an odd number of child models,
``keys`` returns the last child whereas ``values`` and ``items`` ignores it.
``keys`` returns the last child whereas ``values`` and ``items`` ignore it.
"""

def _pretty_str(self):
Expand Down

0 comments on commit a8d4311

Please sign in to comment.