Merge pull request #1811 from Kodiologist/intro-docs-improvements

Overhaul introductory documentation
This commit is contained in:
Kodi Arfer 2019-08-19 14:03:21 -04:00 committed by GitHub
commit 645d2e0b8e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 453 additions and 687 deletions

View File

@ -1,38 +1,22 @@
Hy Hy
== ==
[![Build Status](https://img.shields.io/travis/hylang/hy/master.svg)](https://travis-ci.org/hylang/hy)
[![Version](https://img.shields.io/pypi/v/hy.svg)](https://pypi.python.org/pypi/hy) [![Version](https://img.shields.io/pypi/v/hy.svg)](https://pypi.python.org/pypi/hy)
<a href="https://xkcd.com/224/"><img title="We lost the documentation on quantum mechanics. You'll have to decode the regexes yourself." alt="XKCD #224" src="https://raw.github.com/hylang/shyte/18f6925e08684b0e1f52b2cc2c803989cd62cd91/imgs/xkcd.png"></a> <a href="https://xkcd.com/224/"><img title="We lost the documentation on quantum mechanics. You'll have to decode the regexes yourself." alt="XKCD #224" src="https://raw.github.com/hylang/shyte/18f6925e08684b0e1f52b2cc2c803989cd62cd91/imgs/xkcd.png"></a>
Lisp and Python should love each other. Let's make it happen. [Try it](http://try-hy.appspot.com/). Lisp and Python should love each other. Let's make it happen.
Hylarious Hacks 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.
* [Django + Lisp](https://github.com/paultag/djlisp/tree/master/djlisp) To install the latest stable release of Hy, just use the command `pip3 install
* [Python `sh` Fun](https://twitter.com/paultag/status/314925996442796032) --user hy`. Then you can start an interactive read-eval-print loop (REPL) with
* [Hy IRC Bot](https://github.com/hylang/hygdrop) the command `hy`, or run a Hy program with `hy myprogram.hy`.
* [miniKanren in Hy](https://github.com/algernon/adderall)
OK, so, why? * [Why Hy?](http://docs.hylang.org/en/master/whyhy.html)
------------ * [Tutorial](http://docs.hylang.org/en/master/tutorial.html)
Well. Python is awesome. So awesome, that we have so many tools to alter the
language in a *core* way, but we never use them.
Why?
Well, I wrote Hy to help people realize one thing about Python:
It's really awesome.
Oh, and lisps are neat.
![Cuddles the Hacker](https://i.imgur.com/QbPMXTN.png)
(fan art from the one and only [doctormo](http://doctormo.deviantart.com/art/Cuddles-the-Hacker-372184766))
Project Project
------- -------
@ -41,10 +25,13 @@ Project
* Documentation: * Documentation:
* stable, for use with the latest stable release: http://hylang.org/ * stable, for use with the latest stable release: http://hylang.org/
* master, for use with the latest revision on GitHub: http://docs.hylang.org/en/master * master, for use with the latest revision on GitHub: http://docs.hylang.org/en/master
* Quickstart: http://hylang.org/en/stable/quickstart.html
* Bug reports: We have no bugs! Your bugs are your own! (https://github.com/hylang/hy/issues) * Bug reports: We have no bugs! Your bugs are your own! (https://github.com/hylang/hy/issues)
* License: MIT (Expat) * License: MIT (Expat)
* [Hacking on Hy](http://docs.hylang.org/en/master/hacking.html) * [Hacking on Hy](http://docs.hylang.org/en/master/hacking.html)
* [Contributor Guidelines](http://docs.hylang.org/en/master/hacking.html#contributor-guidelines) * [Contributor Guidelines](http://docs.hylang.org/en/master/hacking.html#contributor-guidelines)
* [Code of Conduct](http://docs.hylang.org/en/master/hacking.html#contributor-code-of-conduct) * [Code of Conduct](http://docs.hylang.org/en/master/hacking.html#contributor-code-of-conduct)
* IRC: Join #hy on [freenode](https://webchat.freenode.net/) * IRC: Join #hy on [freenode](https://webchat.freenode.net/)
![Cuddles the Hacker](https://i.imgur.com/QbPMXTN.png)
(fan art from the one and only [doctormo](http://doctormo.deviantart.com/art/Cuddles-the-Hacker-372184766))

View File

@ -206,6 +206,8 @@ Recursively performs all possible macroexpansions in form, using the ``require``
Macros Macros
====== ======
.. _let:
let let
--- ---

View File

@ -1,3 +1,5 @@
.. _hacking:
=============== ===============
Hacking on Hy Hacking on Hy
=============== ===============

View File

@ -1,36 +1,27 @@
Welcome to Hy's documentation! The Hy Manual
============================== =============
.. image:: _static/hy-logo-small.png .. image:: _static/hy-logo-small.png
:alt: Hy :alt: Hy
:align: left :align: left
:Try Hy: https://try-hy.appspot.com
:PyPI: https://pypi.python.org/pypi/hy :PyPI: https://pypi.python.org/pypi/hy
:Source: https://github.com/hylang/hy :Source: https://github.com/hylang/hy
:List: `hylang-discuss <https://groups.google.com/forum/#!forum/hylang-discuss>`_ :List: `hylang-discuss <https://groups.google.com/forum/#!forum/hylang-discuss>`_
:IRC: ``#hy`` on Freenode :IRC: irc://chat.freenode.net/hy
:Build status:
.. image:: https://secure.travis-ci.org/hylang/hy.png
:alt: Travis CI
:target: http://travis-ci.org/hylang/hy
Hy is a wonderful dialect of Lisp that's embedded in Python. 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.
Since Hy transforms its Lisp code into the Python Abstract Syntax To install the latest stable release of Hy, just use the command ``pip3 install
Tree, you have the whole beautiful world of Python at your fingertips, --user hy``. Then you can start an interactive read-eval-print loop (REPL) with
in Lisp form! the command ``hy``, or run a Hy program with ``hy myprogram.hy``.
Documentation Index
===================
Contents:
.. toctree:: .. toctree::
:maxdepth: 3 :maxdepth: 3
quickstart whyhy
tutorial tutorial
style-guide style-guide
language/index language/index

View File

@ -1,3 +1,5 @@
.. _special-forms:
================= =================
Built-Ins Built-Ins
================= =================
@ -279,6 +281,8 @@ This is completely discarded and doesn't expand to anything, not even ``None``.
Hy Hy
.. _cond:
cond cond
---- ----
@ -338,6 +342,8 @@ is only called on every other value in the list.
(side-effect2 x)) (side-effect2 x))
.. _do:
do do
---------- ----------
@ -400,6 +406,8 @@ the second of which becomes each value.
{0: 0, 1: 10, 2: 20, 3: 30, 4: 40} {0: 0, 1: 10, 2: 20, 3: 30, 4: 40}
.. _setv:
setv setv
---- ----
@ -416,20 +424,19 @@ For example:
=> (counter [1 2 3 4 5 2 3] 2) => (counter [1 2 3 4 5 2 3] 2)
2 2
They can be used to assign multiple variables at once: You can provide more than one targetvalue pair, and the assignments will be made in order::
.. code-block:: hy (setv x 1 y x x 2)
(print x y) ; => 2 1
=> (setv a 1 b 2) You can perform parallel assignments or unpack the source value with square brackets and :ref:`unpack-iterable`::
(1L, 2L)
=> a
1L
=> b
2L
=>
(setv duo ["tim" "eric"])
(setv [guy1 guy2] duo)
(print guy1 guy2) ; => tim eric
``setv`` always returns ``None``. (setv [letter1 letter2 #* others] "abcdefg")
(print letter1 letter2 others) ; => a b ['c', 'd', 'e', 'f', 'g']
setx setx
@ -444,6 +451,8 @@ Whereas ``setv`` creates an assignment statement, ``setx`` creates an assignment
3 is greater than 0 3 is greater than 0
.. _defclass:
defclass defclass
-------- --------
@ -914,6 +923,9 @@ raising an exception.
=> (first []) => (first [])
None None
.. _for:
for for
--- ---
@ -992,6 +1004,8 @@ written without accidental variable name clashes.
Section :ref:`using-gensym` Section :ref:`using-gensym`
.. _get:
get get
--- ---
@ -1022,6 +1036,8 @@ successive elements in a nested structure. Example usage:
index that is out of bounds. index that is out of bounds.
.. _gfor:
gfor gfor
---- ----
@ -1063,6 +1079,8 @@ keyword, the second function would have raised a ``NameError``.
(set-a 5) (set-a 5)
(print-a) (print-a)
.. _if:
if / if* / if-not if / if* / if-not
----------------- -----------------
@ -1188,6 +1206,8 @@ that ``import`` can be used.
(import [sys [*]]) (import [sys [*]])
.. _fn:
fn fn
----------- -----------
@ -1253,6 +1273,8 @@ last
6 6
.. _lfor:
lfor lfor
---- ----
@ -1396,6 +1418,8 @@ print
.. note:: ``print`` always returns ``None``. .. note:: ``print`` always returns ``None``.
.. _quasiquote:
quasiquote quasiquote
---------- ----------
@ -1414,6 +1438,8 @@ using ``unquote`` (``~``). The evaluated form can also be spliced using
; equivalent to '(foo bar baz) ; equivalent to '(foo bar baz)
.. _quote:
quote quote
----- -----
@ -1431,6 +1457,8 @@ alternatively be written using the apostrophe (``'``) symbol.
Hello World Hello World
.. _require:
require require
------- -------
@ -1571,6 +1599,8 @@ sfor
equivalent to ``(set (lfor CLAUSES VALUE))``. See `lfor`_. equivalent to ``(set (lfor CLAUSES VALUE))``. See `lfor`_.
.. _cut:
cut cut
----- -----
@ -1677,6 +1707,8 @@ the given conditional is ``False``. The following shows the expansion of this ma
(do statement)) (do statement))
.. _unpack-iterable:
unpack-iterable, unpack-mapping unpack-iterable, unpack-mapping
------------------------------- -------------------------------
@ -1717,6 +1749,8 @@ more than once in one expression (:pep:`3132`, :pep:`448`).
[1, 2, 3, 4] [1, 2, 3, 4]
.. _unquote:
unquote unquote
------- -------
@ -1792,6 +1826,8 @@ following shows the expansion of the macro.
(if conditional (do statement)) (if conditional (do statement))
.. _while:
while while
----- -----
@ -1851,6 +1887,9 @@ prints
In condition In condition
At end of outer loop At end of outer loop
.. _with:
with with
---- ----

View File

@ -1,3 +1,5 @@
.. _interop:
===================== =====================
Hy <-> Python interop Hy <-> Python interop
===================== =====================

View File

@ -1,3 +1,5 @@
.. _syntax:
============== ==============
Syntax Syntax
============== ==============

View File

@ -1,54 +0,0 @@
==========
Quickstart
==========
.. image:: _static/cuddles-transparent-small.png
:alt: Karen Rustard's Cuddles
(Thanks to Karen Rustad for Cuddles!)
**HOW TO GET HY REAL FAST**:
1. Create a `Virtual Python Environment
<https://pypi.python.org/pypi/virtualenv>`_.
2. Activate your Virtual Python Environment.
3. Install `hy from GitHub <https://github.com/hylang/hy>`_ with ``$ pip install git+https://github.com/hylang/hy.git``.
4. Start a REPL with ``hy``.
5. Type stuff in the REPL::
=> (print "Hy!")
Hy!
=> (defn salutationsnm [name] (print (+ "Hy " name "!")))
=> (salutationsnm "YourName")
Hy YourName!
etc
6. Hit CTRL-D when you're done.
7. If you're familiar with Python, start the REPL using ``hy --spy`` to check what happens inside::
=> (+ "Hyllo " "World" "!")
'Hyllo ' + 'World' + '!'
'Hyllo World!'
*OMG! That's amazing! I want to write a Hy program.*
8. Open up an elite programming editor and type::
#! /usr/bin/env hy
(print "I was going to code in Python syntax, but then I got Hy.")
9. Save as ``awesome.hy``.
10. Make it executable::
chmod +x awesome.hy
11. And run your first Hy program::
./awesome.hy
12. Take a deep breath so as to not hyperventilate.
13. Smile villainously and sneak off to your hydeaway and do
unspeakable things.

View File

@ -2,272 +2,174 @@
Tutorial Tutorial
======== ========
.. TODO .. image:: _static/cuddles-transparent-small.png
.. :alt: Karen Rustard's Cuddles
.. - How do I index into arrays or dictionaries?
.. - Blow your mind with macros!
.. - Where's my banana???
Welcome to the Hy tutorial! This chapter provides a quick introduction to Hy. It assumes a basic background
in programming, but no specific prior knowledge of Python or Lisp.
In a nutshell, Hy is a Lisp dialect, but one that converts its Lisp-stick on a Python
structure into Python ... literally a conversion into Python's abstract ======================
syntax tree! (Or to put it in more crude terms, Hy is lisp-stick on a
Python!)
This is pretty cool because it means Hy is several things: Let's start with the classic::
- A Lisp that feels very Pythonic (print "Hy, world!")
- For Lispers, a great way to use Lisp's crazy powers but in the wide
world of Python's libraries (why yes, you now can write a Django
application in Lisp!)
- For Pythonistas, a great way to start exploring Lisp, from the
comfort of Python!
- For everyone: a pleasant language that has a lot of neat ideas!
This program calls the :func:`print` function, which, like all of Python's
:ref:`built-in functions <py:built-in-funcs>`, is available in Hy.
Basic intro to Lisp for Pythonistas All of Python's :ref:`binary and unary operators <py:expressions>` are
=================================== available, too, although ``==`` is spelled ``=`` in deference to Lisp
tradition. Here's how we'd use the addition operator ``+``::
Okay, maybe you've never used Lisp before, but you've used Python! (+ 1 3)
A "hello world" program in Hy is actually super simple. Let's try it: This code returns ``4``. It's equivalent to ``1 + 3`` in Python and many other
languages. Languages in the `Lisp
<https://en.wikipedia.org/wiki/Lisp_(programming_language)>`_ family, including
Hy, use a prefix syntax: ``+``, just like ``print`` or ``sqrt``, appears before
all of its arguments. The call is delimited by parentheses, but the opening
parenthesis appears before the operator being called instead of after it, so
instead of ``sqrt(2)``, we write ``(sqrt 2)``. Multiple arguments, such as the
two integers in ``(+ 1 3)``, are separated by whitespace. Many operators,
including ``+``, allow more than two arguments: ``(+ 1 2 3)`` is equivalent to
``1 + 2 + 3``.
.. code-block:: clj Here's a more complex example::
(print "hello world") (- (* (+ 1 3 88) 2) 8)
See? Easy! As you may have guessed, this is the same as the Python This code returns ``176``. Why? We can see the infix equivalent with the
version of:: command ``echo "(- (* (+ 1 3 88) 2) 8)" | hy2py``, which returns the Python
code corresponding to the given Hy code, or by passing the ``--spy`` option to
Hy when starting the REPL, which shows the Python equivalent of each input line
before the result. The infix equivalent in this case is:
print("hello world") .. code-block:: python
To add up some super simple math, we could do: ((1 + 3 + 88) * 2) - 8
.. code-block:: clj To evaluate this infix expression, you'd of course evaluate the innermost
parenthesized expression first and work your way outwards. The same goes for
Lisp. Here's what we'd get by evaluating the above Hy code one step at a time::
(+ 1 3) (- (* (+ 1 3 88) 2) 8)
(- (* 92 2) 8)
(- 184 8)
176
Which would return 4 and would be the equivalent of: The basic unit of Lisp syntax, which is similar to a C or Python expression, is
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, macro, or special operator. 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. Special
operators are one of :ref:`a fixed set of names <special-forms>` that are
hard-coded into the compiler, and used to implement everything else.
.. code-block:: clj Comments start with a ``;`` character and continue till the end of the line. A
comment is functionally equivalent to whitespace. ::
1 + 3 (print (** 2 64)) ; Max 64-bit unsigned integer value
What you'll notice is that the first item in the list is the function Although ``#`` isn't a comment character in Hy, a Hy program can begin with a
being called and the rest of the arguments are the arguments being `shebang line <https://en.wikipedia.org/wiki/Shebang_(Unix)>`_, which Hy itself
passed in. In fact, in Hy (as with most Lisps) we can pass in will ignore::
multiple arguments to the plus operator:
.. code-block:: clj #!/usr/bin/env hy
(print "Make me executable, and run me!")
(+ 1 3 55) Literals
========
Which would return 59. Hy has :ref:`literal syntax <syntax>` for all of the same data types that
Python does. Here's an example of Hy code for each type and the Python
equivalent.
Maybe you've heard of Lisp before but don't know much about it. Lisp ============== ================ =================
isn't as hard as you might think, and Hy inherits from Python, so Hy Hy Python Type
is a great way to start learning Lisp. The main thing that's obvious ============== ================ =================
about Lisp is that there's a lot of parentheses. This might seem ``1`` ``1`` :class:`int`
confusing at first, but it isn't so hard. Let's look at some simple ``1.2`` ``1.2`` :class:`float`
math that's wrapped in a bunch of parentheses that we could enter into ``4j`` ``4j`` :class:`complex`
the Hy interpreter: ``True`` ``True`` :class:`bool`
``None`` ``None`` :class:`NoneType`
``"hy"`` ``'hy'`` :class:`str`
``b"hy"`` ``b'hy'`` :class:`bytes`
``(, 1 2 3)`` ``(1, 2, 3)`` :class:`tuple`
``[1 2 3]`` ``[1, 2, 3]`` :class:`list`
``#{1 2 3}`` ``{1, 2, 3}`` :class:`set`
``{1 2 3 4}`` ``{1: 2, 3: 4}`` :class:`dict`
============== ================ =================
.. code-block:: clj In addition, Hy has a Clojure-style literal syntax for
:class:`fractions.Fraction`: ``1/3`` is equivalent to ``fractions.Fraction(1,
3)``.
(setv result (- (/ (+ 1 3 88) 2) 8)) The Hy REPL prints output in Python syntax by default::
This would return 38.0 But why? Well, we could look at the equivalent
expression in python::
result = ((1 + 3 + 88) / 2) - 8
If you were to try to figure out how the above were to work in python,
you'd of course figure out the results by solving each inner
parenthesis. That's the same basic idea in Hy. Let's try this
exercise first in Python::
result = ((1 + 3 + 88) / 2) - 8
# simplified to...
result = (92 / 2) - 8
# simplified to...
result = 46.0 - 8
# simplified to...
result = 38.0
Now let's try the same thing in Hy:
.. code-block:: clj
(setv result (- (/ (+ 1 3 88) 2) 8))
; simplified to...
(setv result (- (/ 92 2) 8))
; simplified to...
(setv result (- 46.0 8))
; simplified to...
(setv result 38.0)
As you probably guessed, this last expression with ``setv`` means to
assign the variable "result" to 38.0.
See? Not too hard!
This is the basic premise of Lisp. Lisp stands for "list
processing"; this means that the structure of the program is
actually lists of lists. (If you're familiar with Python lists,
imagine the entire same structure as above but with square brackets
instead, and you'll be able to see the structure above as both a
program and a data structure.) This is easier to understand with more
examples, so let's write a simple Python program, test it, and then
show the equivalent Hy program::
def simple_conversation():
print("Hello! I'd like to get to know you. Tell me about yourself!")
name = input("What is your name? ")
age = input("What is your age? ")
print("Hello " + name + "! I see you are " + age + " years old.")
simple_conversation()
If we ran this program, it might go like::
Hello! I'd like to get to know you. Tell me about yourself!
What is your name? Gary
What is your age? 38
Hello Gary! I see you are 38 years old.
Now let's look at the equivalent Hy program:
.. code-block:: clj
(defn simple-conversation []
(print "Hello! I'd like to get to know you. Tell me about yourself!")
(setv name (input "What is your name? "))
(setv age (input "What is your age? "))
(print (+ "Hello " name "! I see you are "
age " years old.")))
(simple-conversation)
If you look at the above program, as long as you remember that the
first element in each list of the program is the function (or
macro... we'll get to those later) being called and that the rest are
the arguments, it's pretty easy to figure out what this all means.
(As you probably also guessed, ``defn`` is the Hy method of defining
methods.)
Still, lots of people find this confusing at first because there's so
many parentheses, but there are plenty of things that can help make
this easier: keep indentation nice and use an editor with parenthesis
matching (this will help you figure out what each parenthesis pairs up
with) and things will start to feel comfortable.
There are some advantages to having a code structure that's actually a
very simple data structure as the core of Lisp is based on. For one
thing, it means that your programs are easy to parse and that the
entire actual structure of the program is very clearly exposed to you.
(There's an extra step in Hy where the structure you see is converted
to Python's own representations ... in "purer" Lisps such as Common
Lisp or Emacs Lisp, the data structure you see in the code and the
data structure that is executed is much more literally close.)
Another implication of this is macros: if a program's structure is a
simple data structure, that means you can write code that can write
code very easily, meaning that implementing entirely new language
features can be very fast. Previous to Hy, this wasn't very possible
for Python programmers ... now you too can make use of macros'
incredible power (just be careful to not aim them footward)!
Hy is a Lisp-flavored Python
============================
Hy converts to Python's own abstract syntax tree, so you'll soon start
to find that all the familiar power of python is at your fingertips.
You have full access to Python's data types and standard library in
Hy. Let's experiment with this in the hy interpreter::
=> [1 2 3] => [1 2 3]
[1, 2, 3] [1, 2, 3]
=> {"dog" "bark"
... "cat" "meow"}
{'dog': 'bark', 'cat': 'meow'}
=> (, 1 2 3)
(1, 2, 3)
=> #{3 1 2}
{1, 2, 3}
=> 1/2
Fraction(1, 2)
Notice the last two lines: Hy has a fraction literal like Clojure. But if you start Hy like this (a shell alias might be helpful)::
If you start Hy like this (a shell alias might be helpful)::
$ hy --repl-output-fn=hy.contrib.hy-repr.hy-repr $ hy --repl-output-fn=hy.contrib.hy-repr.hy-repr
the interactive mode will use :ref:`hy-repr-fn` instead of Python's the interactive mode will use :ref:`hy-repr-fn` instead of Python's native
native ``repr`` function to print out values, so you'll see values in ``repr`` function to print out values, so you'll see values in Hy syntax::
Hy syntax rather than Python syntax::
=> [1 2 3] => [1 2 3]
[1 2 3] [1 2 3]
=> {"dog" "bark"
... "cat" "meow"}
{"dog" "bark" "cat" "meow"}
If you are familiar with other Lisps, you may be interested that Hy
supports the Common Lisp method of quoting:
.. code-block:: clj Basic operations
================
=> '(1 2 3) Set variables with :ref:`setv`::
(1 2 3)
You also have access to all the built-in types' nice methods:: (setv zone-plane 8)
=> (.strip " fooooo ") Access the elements of a list, dictionary, or other data structure with
"fooooo" :ref:`get`::
What's this? Yes indeed, this is precisely the same as:: (setv fruit ["apple" "banana" "cantaloupe"])
(print (get fruit 0)) ; => apple
(setv (get fruit 1) "durian")
(print (get fruit 1)) ; => durian
" fooooo ".strip() Access a range of elements in an ordered structure with :ref:`cut`::
That's right---Lisp with dot notation! If we have this string (print (cut "abcdef" 1 4)) ; => bcd
assigned as a variable, we can also do the following:
.. code-block:: clj Conditional logic can be built with :ref:`if`::
(setv this-string " fooooo ") (if (= 1 1)
(this-string.strip) (print "Math works. The universe is safe.")
(print "Math has failed. The universe is doomed."))
What about conditionals?: As in this example, ``if`` is called like ``(if CONDITION THEN ELSE)``. It
executes and returns the form ``THEN`` if ``CONDITION`` is true (according to
:class:`bool`) and ``ELSE`` otherwise. If ``ELSE`` is omitted, ``None`` is used
in its place.
.. code-block:: clj What if you want to use more than form in place of the ``THEN`` or ``ELSE``
clauses, or in place of ``CONDITION``, for that matter? Use the special
operator :ref:`do` (known more traditionally in Lisp as ``progn``), which
combines several forms into one, returning the last::
(if (try-some-thing) (if (do (print "Let's check.") (= 1 1))
(print "this is if true") (do
(print "this is if false")) (print "Math works.")
(print "The universe is safe."))
(do
(print "Math has failed.")
(print "The universe is doomed.")))
As you can tell above, the first argument to ``if`` is a truth test, the For branching on more than one case, try :ref:`cond`::
second argument is the body if true, and the third argument (optional!)
is if false (ie. ``else``).
If you need to do more complex conditionals, you'll find that you
don't have ``elif`` available in Hy. Instead, you should use something
called ``cond``. In Python, you might do something like::
somevar = 33
if somevar > 50:
print("That variable is too big!")
elif somevar < 10:
print("That variable is too small!")
else:
print("That variable is jussssst right!")
In Hy, you would do:
.. code-block:: clj
(setv somevar 33) (setv somevar 33)
(cond (cond
@ -278,306 +180,140 @@ In Hy, you would do:
[True [True
(print "That variable is jussssst right!")]) (print "That variable is jussssst right!")])
What you'll notice is that ``cond`` switches off between a statement The macro ``(when CONDITION THEN-1 THEN-2 …)`` is shorthand for ``(if CONDITION
that is executed and checked conditionally for true or falseness, and (do THEN-1 THEN-2 …))``. ``unless`` works the same as ``when``, but inverts the
then a bit of code to execute if it turns out to be true. You'll also condition with ``not``.
notice that the ``else`` is implemented at the end simply by checking
for ``True`` -- that's because ``True`` will always be true, so if we get
this far, we'll always run that one!
You might notice above that if you have code like: Hy's basic loops are :ref:`while` and :ref:`for`::
.. code-block:: clj (setv x 3)
(while (> x 0)
(print x)
(setv x (- x 1))) ; => 3 2 1
(if some-condition (for [x [1 2 3]]
(body-if-true) (print x)) ; => 1 2 3
(body-if-false))
But wait! What if you want to execute more than one statement in the A more functional way to iterate is provided by the comprehension forms such as
body of one of these? :ref:`lfor`. Whereas ``for`` always returns ``None``, ``lfor`` returns a list
with one element per iteration. ::
You can do the following: (print (lfor x [1 2 3] (* x 2))) ; => [2, 4, 6]
.. code-block:: clj
(if (try-some-thing) Functions, classes, and modules
(do ===============================
(print "this is if true")
(print "and why not, let's keep talking about how true it is!"))
(print "this one's still simply just false"))
You can see that we used ``do`` to wrap multiple statements. If you're Define named functions with :ref:`defn`::
familiar with other Lisps, this is the equivalent of ``progn``
elsewhere.
Comments start with semicolons: (defn fib [n]
(if (< n 2)
n
(+ (fib (- n 1)) (fib (- n 2)))))
(print (fib 8)) ; => 21
.. code-block:: clj Define anonymous functions with :ref:`fn`::
(print "this will run") (print (list (filter (fn [x] (% x 2)) (range 10))))
; (print "but this will not") ; => [1, 3, 5, 7, 9]
(+ 1 2 3) ; we'll execute the addition, but not this comment!
Hashbang (``#!``) syntax is supported: Special symbols in the parameter list of ``defn`` or ``fn`` allow you to
indicate optional arguments, provide default values, and collect unlisted
arguments::
.. code-block:: clj (defn test [a b &optional c [d "x"] &rest e]
[a b c d e])
(print (test 1 2)) ; => [1, 2, None, 'x', ()]
(print (test 1 2 3 4 5 6 7)) ; => [1, 2, 3, 4, (5, 6, 7)]
#! /usr/bin/env hy Set a function parameter by name with a ``:keyword``::
(print "Make me executable, and run me!")
Looping is not hard but has a kind of special structure. In Python, (test 1 2 :d "y") ; => [1, 2, None, 'y', ()]
we might do::
for i in range(10): Define classes with :ref:`defclass`::
print("'i' is now at " + str(i))
The equivalent in Hy would be: (defclass FooBar []
(defn __init__ [self x]
(setv self.x x))
(defn get-x [self]
self.x))
.. code-block:: clj Here we create a new instance ``fb`` of ``FooBar`` and access its attributes by
various means::
(for [i (range 10)] (setv fb (FooBar 15))
(print (+ "'i' is now at " (str i)))) (print fb.x) ; => 15
(print (. fb x)) ; => 15
(print (.get-x fb)) ; => 15
(print (fb.get-x)) ; => 15
Python's collections indexes and slices are implemented Note that syntax like ``fb.x`` and ``fb.get-x`` only works when the object
by the ``get`` and ``cut`` built-in: being invoked (``fb``, in this case) is a simple variable name. To get an
attribute or call a method of an arbitrary form ``FORM``, you must use the
syntax ``(. FORM x)`` or ``(.get-x FORM)``.
.. code-block:: clj Access an external module, whether written in Python or Hy, with
:ref:`import`::
(setv array [0 1 2]) (import math)
(get array 1) (print (math.sqrt 2)) ; => 1.4142135623730951
(cut array -3 -1)
which is equivalent to:: 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
array[1] running a Hy program.
array[-3:-1]
You can also import and make use of various Python libraries. For
example:
.. code-block:: clj
(import os)
(if (os.path.isdir "/tmp/somedir")
(os.mkdir "/tmp/somedir/anotherdir")
(print "Hey, that path isn't there!"))
Python's context managers (``with`` statements) are used like this:
.. code-block:: clj
(with [f (open "/tmp/data.in")]
(print (.read f)))
which is equivalent to::
with open("/tmp/data.in") as f:
print(f.read())
And yes, we do have List comprehensions! In Python you might do::
odds_squared = [
pow(num, 2)
for num in range(100)
if num % 2 == 1]
In Hy, you could do these like:
.. code-block:: clj
(setv odds-squared
(lfor
num (range 100)
:if (= (% num 2) 1)
(pow num 2)))
.. code-block:: clj
; And, an example stolen shamelessly from a Clojure page:
; Let's list all the blocks of a Chessboard:
(lfor
x (range 8)
y "ABCDEFGH"
(, x y))
; [(0, 'A'), (0, 'B'), (0, 'C'), (0, 'D'), (0, 'E'), (0, 'F'), (0, 'G'), (0, 'H'),
; (1, 'A'), (1, 'B'), (1, 'C'), (1, 'D'), (1, 'E'), (1, 'F'), (1, 'G'), (1, 'H'),
; (2, 'A'), (2, 'B'), (2, 'C'), (2, 'D'), (2, 'E'), (2, 'F'), (2, 'G'), (2, 'H'),
; (3, 'A'), (3, 'B'), (3, 'C'), (3, 'D'), (3, 'E'), (3, 'F'), (3, 'G'), (3, 'H'),
; (4, 'A'), (4, 'B'), (4, 'C'), (4, 'D'), (4, 'E'), (4, 'F'), (4, 'G'), (4, 'H'),
; (5, 'A'), (5, 'B'), (5, 'C'), (5, 'D'), (5, 'E'), (5, 'F'), (5, 'G'), (5, 'H'),
; (6, 'A'), (6, 'B'), (6, 'C'), (6, 'D'), (6, 'E'), (6, 'F'), (6, 'G'), (6, 'H'),
; (7, 'A'), (7, 'B'), (7, 'C'), (7, 'D'), (7, 'E'), (7, 'F'), (7, 'G'), (7, 'H')]
Python has support for various fancy argument and keyword arguments.
In Python we might see::
>>> def optional_arg(pos1, pos2, keyword1=None, keyword2=42):
... return [pos1, pos2, keyword1, keyword2]
...
>>> optional_arg(1, 2)
[1, 2, None, 42]
>>> optional_arg(1, 2, 3, 4)
[1, 2, 3, 4]
>>> optional_arg(keyword1=1, pos2=2, pos1=3, keyword2=4)
[3, 2, 1, 4]
The same thing in Hy::
=> (defn optional-arg [pos1 pos2 &optional keyword1 [keyword2 42]]
... [pos1 pos2 keyword1 keyword2])
=> (optional-arg 1 2)
[1 2 None 42]
=> (optional-arg 1 2 3 4)
[1 2 3 4]
You can call keyword arguments like this::
=> (optional-arg :keyword1 1
... :pos2 2
... :pos1 3
... :keyword2 4)
[3, 2, 1, 4]
You can unpack arguments with the syntax ``#* args`` and ``#** kwargs``,
similar to `*args` and `**kwargs` in Python::
=> (setv args [1 2])
=> (setv kwargs {"keyword2" 3
... "keyword1" 4})
=> (optional-arg #* args #** kwargs)
[1, 2, 4, 3]
Hy also supports ``*args`` and ``**kwargs`` in parameter lists. In Python::
def some_func(foo, bar, *args, **kwargs):
import pprint
pprint.pprint((foo, bar, args, kwargs))
The Hy equivalent:
.. code-block:: clj
(defn some-func [foo bar &rest args &kwargs kwargs]
(import pprint)
(pprint.pprint (, foo bar args kwargs)))
Finally, of course we need classes! In Python, we might have a class
like::
class FooBar(object):
"""
Yet Another Example Class
"""
def __init__(self, x):
self.x = x
def get_x(self):
"""
Return our copy of x
"""
return self.x
And we might use it like::
bar = FooBar(1)
print(bar.get_x())
In Hy:
.. code-block:: clj
(defclass FooBar [object]
"Yet Another Example Class"
(defn --init-- [self x]
(setv self.x x))
(defn get-x [self]
"Return our copy of x"
self.x))
And we can use it like:
.. code-block:: clj
(setv bar (FooBar 1))
(print (bar.get-x))
Or using the leading dot syntax!
.. code-block:: clj
(print (.get-x (FooBar 1)))
You can also do class-level attributes. In Python::
class Customer(models.Model):
name = models.CharField(max_length=255)
address = models.TextField()
notes = models.TextField()
In Hy:
.. code-block:: clj
(defclass Customer [models.Model]
(setv name (models.CharField :max-length 255))
(setv address (models.TextField))
(setv notes (models.TextField)))
Macros Macros
====== ======
One really powerful feature of Hy are macros. They are small functions that are Macros are the basic metaprogramming tool of Lisp. A macro is a function that
used to generate code (or data). When a program written in Hy is started, the is called at compile time (i.e., when a Hy program is being translated to
macros are executed and their output is placed in the program source. After this, Python :mod:`ast` objects) and returns code, which becomes part of the final
the program starts executing normally. Very simple example: program. Here's a simple example::
.. code-block:: clj (print "Executing")
(defmacro m []
(print "Now for a slow computation")
(setv x (% (** 10 10 7) 3))
(print "Done computing")
x)
(print "Value:" (m))
(print "Done executing")
=> (defmacro hello [person] If you run this program twice in a row, you'll see this::
... `(print "Hello there," ~person))
=> (hello "Tuukka")
Hello there, Tuukka
The thing to notice here is that hello macro doesn't output anything on $ hy example.hy
screen. Instead it creates piece of code that is then executed and prints on Now for a slow computation
screen. This macro writes a piece of program that looks like this (provided that Done computing
we used "Tuukka" as parameter): Executing
Value: 1
Done executing
$ hy example.hy
Executing
Value: 1
Done executing
.. code-block:: clj The slow computation is performed while compiling the program on its first
invocation. Only after the whole program is compiled does normal execution
begin from the top, printing "Executing". When the program is called a second
time, it is run from the previously compiled bytecode, which is equivalent to
simply::
(print "Hello there," "Tuukka") (print "Executing")
(print "Value:" 1)
(print "Done executing")
We can also manipulate code with macros: 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
.. code-block:: clj arbitrary Hy forms to be executed as code. There are several special operators
and macros that make it easy to construct forms programmatically, such as
=> (defmacro rev [code] :ref:`quote` (``'``), :ref:`quasiquote` (`````), :ref:`unquote` (``~``), and
... (setv op (last code) params (list (butlast code))) :ref:`defmacro!`. The previous chapter has :ref:`a simple example <do-while>`
... `(~op ~@params)) of using ````` and ``~`` to define a new control construct ``do-while``.
=> (rev (1 2 3 +))
6
The code that was generated with this macro just switched around some of the
elements, so by the time program started executing, it actually reads:
.. code-block:: clj
(+ 1 2 3)
Sometimes it's nice to be able to call a one-parameter macro without Sometimes it's nice to be able to call a one-parameter macro without
parentheses. Tag macros allow this. The name of a tag macro is typically parentheses. Tag macros allow this. The name of a tag macro is often just one
one character long, but since Hy operates well with Unicode, we aren't running character long, but since Hy allows most Unicode characters in the name of a
out of characters that soon: macro (or ordinary variable), you won't out of characters soon. ::
.. code-block:: clj
=> (deftag ↻ [code] => (deftag ↻ [code]
... (setv op (last code) params (list (butlast code))) ... (setv op (last code) params (list (butlast code)))
@ -585,106 +321,23 @@ out of characters that soon:
=> #↻(1 2 3 +) => #↻(1 2 3 +)
6 6
Macros are useful when one wishes to extend Hy or write their own What if you want to use a macro that's defined in a different module?
language on top of that. Many features of Hy are macros, like ``when``, ``import`` won't help, because it merely translates to a Python ``import``
``cond`` and ``->``. statement that's executed at run-time, and macros are expanded at compile-time,
that is, during the translation from Hy to Python. Instead, use :ref:`require`,
What if you want to use a macro that's defined in a different which imports the module and makes macros available at compile-time.
module? The special form ``import`` won't help, because it merely ``require`` uses the same syntax as ``import``. ::
translates to a Python ``import`` statement that's executed at
run-time, and macros are expanded at compile-time, that is,
during the translate from Hy to Python. Instead, use ``require``,
which imports the module and makes macros available at
compile-time. ``require`` uses the same syntax as ``import``.
.. code-block:: clj
=> (require tutorial.macros) => (require tutorial.macros)
=> (tutorial.macros.rev (1 2 3 +)) => (tutorial.macros.rev (1 2 3 +))
6 6
Hy <-> Python interop Next steps
===================== ==========
Using Hy from Python You now know enough to be dangerous with Hy. You may now smile villainously and
-------------------- sneak off to your Hydeaway to do unspeakable things.
You can use Hy modules in Python! Refer to Python's documention for the details of Python semantics, and the rest
of this manual for Hy-specific features. Like Hy itself, the manual is
If you save the following in ``greetings.hy``: incomplete, but :ref:`contributions <hacking>` are always welcome.
.. code-block:: clj
(defn greet [name] (print "hello from hy," name))
Then you can use it directly from Python, by importing Hy before importing
the module. In Python::
import hy
import greetings
greetings.greet("Foo")
Using Python from Hy
--------------------
You can also use any Python module in Hy!
If you save the following in ``greetings.py`` in Python::
def greet(name):
print("hello, %s" % (name))
You can use it in Hy (see :ref:`import`):
.. code-block:: clj
(import greetings)
(.greet greetings "foo")
More information on :doc:`../language/interop`.
Protips!
========
Hy also features something known as the "threading macro", a really neat
feature of Clojure's. The "threading macro" (written as ``->``) is used
to avoid deep nesting of expressions.
The threading macro inserts each expression into the next expression's first
argument place.
Let's take the classic:
.. code-block:: clj
(require [hy.contrib.loop [loop]])
(loop (print (eval (read))))
Rather than write it like that, we can write it as follows:
.. code-block:: clj
(require [hy.contrib.loop [loop]])
(-> (read) (eval) (print) (loop))
Now, using `python-sh <http://amoffat.github.com/sh/>`_, we can show
how the threading macro (because of python-sh's setup) can be used like
a pipe:
.. code-block:: clj
=> (import [sh [cat grep wc]])
=> (-> (cat "/usr/share/dict/words") (grep "-E" "^hy") (wc "-l"))
210
Which, of course, expands out to:
.. code-block:: clj
(wc (grep (cat "/usr/share/dict/words") "-E" "^hy") "-l")
Much more readable, no? Use the threading macro!

142
docs/whyhy.rst Normal file
View File

@ -0,0 +1,142 @@
=======
Why Hy?
=======
Hy is a multi-paradigm general-purpose programming language in the `Lisp family
<https://en.wikipedia.org/wiki/Lisp_(programming_language)>`_. It's implemented
as a kind of alternative syntax for Python. Compared to Python, Hy offers a
variety of extra features, generalizations, and syntactic simplifications, as
would be expected of a Lisp. Compared to other Lisps, Hy provides direct access
to Python's built-ins and third-party Python libraries, while allowing you to
freely mix imperative, functional, and object-oriented styles of programming.
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 parentheses 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.
.. _do-while:
::
(defmacro do-while [condition &rest body]
`(do
~body
(while ~condition
~body)))
(setv x 0)
(do-while x
(print "This line is executed 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,
to return values. They can only execute a set of statements:
.. code-block:: python
with open("foo") as o:
f1 = o.read()
with open("bar") as o:
f2 = o.read()
print(len(f1) + len(f2))
In Hy, :ref:`with` returns the value of its last body form, so you can use it
like an ordinary function call::
(print (+
(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 :ref:`generator
expression <gfor>`::
(print (sum (gfor
filename ["foo" "bar"]
(len (with [o (open filename)] (.read o))))))
Finally, Hy offers several generalizations to Python's binary operators.
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)``.
The Hy compiler works by reading Hy source code into Hy model objects 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.
You can even :ref:`mix Python and Hy code in the same project <interop>`, which
can be a good way to get your feet wet in Hy.
Hy versus other Lisps
---------------------
At run-time, Hy is essentially Python code. Thus, while Hy's design owes a lot
to `Clojure <https://clojure.org>`_, it is more tightly coupled to Python than
Clojure is to Java; a better analogy is `CoffeeScript's
<https://coffeescript.org>`_ relationship to JavaScript. Python's built-in
:ref:`functions <py:built-in-funcs>` and :ref:`data structures
<py:bltin-types>` are directly available::
(print (int "deadbeef" :base 16)) ; 3735928559
(print (len [1 10 100])) ; 3
The same goes for third-party Python libraries from `PyPI <https://pypi.org>`_
and elsewhere. Here's a tiny `CherryPy <https://cherrypy.org>`_ web application
in Hy::
(import cherrypy)
(defclass HelloWorld []
(#@ cherrypy.expose (defn index [self]
"Hello World!")))
(cherrypy.quickstart (HelloWorld))
You can even run Hy on `PyPy <https://pypy.org>`_ for a particularly speedy
Lisp.
Like all Lisps, Hy is `homoiconic
<https://en.wikipedia.org/wiki/Homoiconicity>`_. Its syntax is represented not
with cons cells or with Python's basic data structures, but with simple
subclasses of Python's basic data structures called :ref:`models <models>`.
Using models in place of plain ``list``\s, ``set``\s, and so on has two
purposes: models can keep track of their line and column numbers for the
benefit of error messages, and models can represent syntactic features that the
corresponding primitive type can't, such as the order in which elements appear
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 ``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
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
aforementioned mixing of statements and expressions, :ref:`name mangling
<mangling>` that transparently converts symbols with names like ``valid?`` to
Python-legal identifiers, and a :ref:`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.