Hy Documentation

repository·master·Indexed 26 days ago

https://github.com/hylang/hy

Hy is a Lisp dialect embedded in Python that transforms Lisp code into Python abstract syntax tree (AST) objects. It allows developers to use the entire Python ecosystem using Lisp syntax, featuring macros for sequential and compile-time evaluation, Python code embedding via py and pys, and comprehensive support for Python's control flow, including match statements, comprehensions (lfor, dfor, gfor, sfor), and exception handling.

Tokens
16.2K
Snippets
61
Records
119
Agent score
88%

What's inside Hy

  1. Understand Hy's relationship with Python

    master
    Hy is a Lisp-family programming language implemented as an alternative syntax for Python. It is not a standalone runtime; instead, it compiles Hy source code into Python Abstract Syntax Tree (AST) objects, which are then executed by the Python interpreter. This allows for direct access to Python's built-ins, data structures, and any third-party libraries available via PyPI. You can mix Python and Hy code within the same project or even the same file.
  2. Use hy.model-patterns for tree parsing

    master

    The hy.model-patterns module provides a library of parser combinators designed to parse complex trees of Hy models. It allows you to concisely express the general structure of a model tree (similar to regular expressions for text) to validate and extract components. This is particularly useful for implementing compilers or writing complex macros.

    To run a parser, use the .parse method on the parser object: (.parse parser form). If the parse fails, it raises funcparserlib.parser.NoParseError.

    (import funcparserlib.parser [maybe many]
            hy.model-patterns *)
    
    (setv form '(try (foo1) (foo2) (except [EType1] (foo3))))
    
    (setv parser (whole [
      (sym "try")
      (many (notpexpr "except" "else" "finally"))
      (many (pexpr (sym "except") (| (brackets) (brackets FORM) (brackets SYM FORM)) (many FORM))))
    ]))
    
    (setv result (.parse parser form))
  3. Use comments and discard prefixes in Hy

    master

    Hy provides two ways to comment out code:

    1. Semicolon (;): Standard line comments. Everything from the ; to the end of the line is ignored. These cannot be used to discard forms mid-structure (e.g., [dilly ; and krunk] results in an unclosed list [dilly).
    2. Discard Prefix (#_): An extensible data notation discard prefix. It discards the following single form. Unlike semicolon comments, reader macros are still executed for the discarded form, and parsing resumes immediately after the form ends. This allows for structure-aware commenting (e.g., [dilly #_ and krunk] is equivalent to [dilly krunk]).
  4. Evaluate expressions and method calls

    master

    Expressions are denoted by parentheses ( ... ). The first element is the head.

    Evaluation Logic:

    1. Macros: If the head is a symbol and a macro is defined, the macro is called.
      • Exception: If the head is a hy.pyops function and an argument is unpack-iterable, the pyops version is called (e.g., (+ #* summands) becomes (hy.pyops.+ #* summands)).
    2. Method Calls: If the head is an expression of the form (. None ...), it constructs a method call.
      • Example: (.add my_set 5) is equivalent to ((. my_set add) 5), which calls my_set.add(5) in Python.
      • Special Case: (hy.R.module.macro ...) requires the module and calls the macro without bringing it into the local scope.
    3. Standard Calls: Otherwise, the expression is compiled into a Python-level call where the head is the calling object and remaining forms are arguments.
  5. Understand Hy versioning and Python compatibility

    master

    Hy follows semantic versioning (SemVer).

    • Breaking Changes: For a summary of user-visible changes and instructions on how to update code during breaking changes, refer to the NEWS.rst file in the repository.
    • Python Compatibility: Hy is tested on all released and maintained versions of CPython (Linux, Windows, Mac OS) and recent versions of PyPy.
    • Version Drops: Hy may drop support for Python versions after CPython ceases maintenance. Such changes are considered non-breaking and will result in a minor version bump rather than a major version bump.
    • Installation Safety: The python_requires field in Hy's setup.py is used to prevent installing a version of Hy that is incompatible with your current Python version.
  6. Use sequential forms and literals

    master

    Hy uses specific syntax for different collection types:

    • Lists: Denoted by [ ... ] (e.g., [1 2 3]).
    • Tuples: Denoted by #( ... ) (e.g., #(1 2 3)). Note: () is a legal empty expression at the reader level but cannot be compiled; use #( ) for an empty tuple.
    • Sets: Denoted by #{ ... } (e.g., #{1 2 3}).
    • Dictionaries: Denoted by { ... }. Even-numbered child forms are keys, odd-numbered are values (e.g., {"a" 1 "b" 2}).
    • Sequences: Nested forms comprising any number of other forms in a defined order.
  7. Use F-strings and T-strings

    master

    Hy provides string-like compound constructs for interpolation.

    F-strings (Format Strings):

    • Prefix with f.
    • Embedded code is written in Hy, not Python.
    • Whitespace Rule: Because =, !, and : are identifier characters, you may need whitespace to separate a conversion specifier from a format specifier.
    • Example: f"{foo :x<5}"

    T-strings (Template Strings):

    • Prefix with t (requires Hy 1.3; compilation requires Python 3.14+).
    • Evaluates to a string.templatelib.Template object containing string and expression components without immediate interpolation.

    Examples:

    (print f"The sum is {(+ 1 1)}.")
    (print (hy.repr t"The sum is {(+ 1 1)}."))
  8. Compare Hy syntax to Python

    master

    Hy uses Lisp's traditional prefix syntax with parentheses instead of Python's C-like infix syntax. Because structure is indicated by punctuation rather than whitespace, Hy is free-form and convenient for command-line use.

    Key syntactic differences include:

    • Prefix Notation: (print "The answer is" (+ 2 (.method object arg))) instead of print("The answer is", 2 + object.method(arg)).
    • Expression-based with: Unlike Python, Hy's with form returns the value of its last body form, allowing it to be used in expressions.
    • Generalized Operators: Binary operators can take more than two arguments (e.g., (+ 1 2 3)) and are available as first-class functions (e.g., + from hy.pyops).
  9. Understand Hy Models and their relationship to Python values

    master

    Hy programs are parsed into a nested structure of models. Models represent the abstract syntax of the code. While many models are subclasses of Python types (e.g., hy.models.Integer is a subclass of int), a model is not strictly equal to the value it represents. For example, (= (hy.models.String "foo") "foo") returns False because one is a model and the other is a raw Python string.

    To bridge the gap between models and Python values, you can:

    • Promote a value to a model using hy.as-model.
    • Demote a model to a Python value using standard Python constructors like str() or int().
    • Evaluate a model as Hy code using hy.eval.

    Note: If you are managing plain data (like a list of email addresses) and do not need to generate Hy source code, use standard Python data structures (list, dict, tuple) instead of Hy models (hy.models.List, etc.) for better performance and simplicity.

  10. Access Python reserved words from Hy using Keyword Mincing

    master

    If you need to refer to a Python variable that has the same name as a Hy reserved word (e.g., break), you can use Unicode normalization (NFKC) to create a valid Python identifier. For example, while (setv break 13) is valid Hy, my_module.break is invalid Python. You can use mathematical bold small letters to bypass this:

    𝐚𝐛𝐜𝐝𝐞𝐟𝐠𝐡𝐢𝐣𝐤𝐥𝐦𝐧𝐨𝐩𝐪𝐫𝐬𝐭𝐮𝐯𝐰𝐱𝐲𝐳

    𝐚𝐛𝐜𝐝𝐞𝐟𝐠𝐡𝐢𝐣𝐤𝐥𝐦𝐧𝐨𝐩𝐪𝐫𝐬𝐭𝐮𝐯𝐰𝐱𝐲𝐳