Bootstrap

HY编程快速入门实践课第四章 深入学HY语法

学习完上一章 HY编程快速入门实践课第三章 HY宏入门-CSDN博客

我们对HY宏编程有了初步了解,现在来系统学一下HY的语法。本章文档参考:Syntax — Hy 0.29.0 manual

宏相关语法糖

This is all resolved at the reader level, so the model that gets produced is the same whether you take your code with sugar or without.

Macro

Syntax

quote

'FORM

quasiquote

`FORM

unquote

~FORM

unquote-splice

~@FORM

unpack-iterable

#* FORM

unpack-mapping

#** FORM

 quote 引号,是双引号下面的那个单引号'

quasiquote 反引号,是左上角波浪线下面的那个引号`

unquote 波浪线 取消引用~

unquote-splice 取消引用并展开 波浪线+@ ~@

unpck-iterable 取消引用并迭代 使用#*

unpack-mapping 取消引用并映射 #**

  1. quasiquote(准引号)
    • 符号:反引号 `
    • 用途:用于创建字面列表或向量,但允许在内部嵌入通过 unquote 和 unquote-splice 求值的表达式。
  2. unquote(取消引用)
    • 符号:波浪线 ~
    • 用途:在 quasiquote 表达式内部使用,用于指示某个部分应该被求值而不是作为字面量。
  3. unquote-splice(取消引用并展开)
    • 符号:波浪线后跟 @ 符号 ~@
    • 用途:在 quasiquote 表达式内部使用,与 unquote 类似,但专门用于列表或向量,将其内容展开为多个元素。
  4. unpack-iterable(非标准) 和 unpack-mapping(非标准)
    • 用于在宏展开时解包可迭代对象(如列表)或映射(如哈希表)。
    • 符号:unpack-iterable用#*  unpack-mapping用#** 
=> (setv lst [ 1 2 3])  
=> lst
[1 2 3]
=> (setv quasi-lst `[1, lst 4])
=> quasi-lst
'[1 lst 4]
=> (setv quasi-lst1 `[1 lst 4])
=> quasi-lst1
'[1 lst 4]
=> (setv quasi-lst1 `[1 ~lst 4])
=> quasi-lst1
'[1 [1 2 3] 4]
=> [1 lst]
[1 [1 2 3]]

=> [1 `~lst]
[1 [1 2 3]]
=> [1 `~lst]
[1 [1 2 3]]
=> [1 '~lst]
[1 '~lst]

 

quote 引号,是双引号下面的那个单引号'

直接引用后面的表达式,不执行,有点像python里的单引号和双引号。hy手册中的描述:

返回给定的模型而不进行评估。或者更为迂腐的是,quote遵循生成并返回最初调用的模型的代码。因此,quote充当了模型构造函数的语法糖

(quote a)
  ; Equivalent to:  (hy.models.Symbol "a")
(quote (+ 1 1))
  ; Equivalent to:  (hy.models.Expression [
  ;   (hy.models.Symbol "+")
  ;   (hy.models.Integer 1)
  ;   (hy.models.Integer 1)])

 可以直接用单引号代替quote

=> 'a
'a
=> '(+ 1 1)
'(+ 1 1)

quasiquote 反引号,是左上角波浪线下面的那个引号`

跟引号类似,只是表达式里面有些符合要求的会被求值。hy手册中说:

准引号与引号类似,只是它将模型视为模板,其中某些特殊表达式表示某些代码应该被求值,并在那里替换其值。这个想法类似于C的sprintf或Python的各种字符串格式构造。

=> (setv x 2)
=> (quasiquote (+ 1 (unquote x)))  ; => '(+ 1 2)
'(+ 1 2)


=> `(+ 1 ~x)
'(+ 1 2)

可以看到,表达式里面使用unquote的地方,进行了求值操作。如果使用quote引号,那么里面即使用了unquote,也会原封不动的表达出来

=> '(+ 1 ~x)
'(+ 1 ~x)

 unquote 波浪线~ 取消引用

在 quasiquote 表达式内部使用,用于指示某个部分应该被求值而不是作为字面量。就像前面的例子里,x取消引用,也就是要对x进行求值。记住unquote 波浪线~ 应用在quasiquote反引号表达式内部。也就是有unquote~,表达式前面就应该有quasiquote` 。

看个例子

=> (defmacro set-foo [value]
...   `(setv foo ~value))
=> (set-foo (+ 1 2 3))
=> (print foo)  ; => 6
6

 unquote-splice(取消引用并展开)

也是在quasiquote反引号内部使用,符号是波浪线后跟 @ 符号 ~@ ,与 unquote 类似,但专门用于列表或向量,将其内容展开为多个元素。

=> (setv X [1 2 3])
=> `[a b ~X c d ~@X e f]
'[a b [1 2 3] c d 1 2 3 e f]

第一个 ~X展开为[1 2 3] 第二个 ~@X 展开为1 2 3 ,可见 ~@把列表展开了,也就是去掉了列表的中括号[ ] 

unpck-iterable 取消引用并迭代(迭代解包)

符号:unpack-iterable用#* ,hy手册:

(也称为splat运算符、星形运算符、自变量扩展、自变量爆炸、自变量收集和可变参数等…)
迭代解包和映射解包允许可迭代或映射对象(分别)向函数提供位置或关键字参数。

=> [(unpack-iterable [1 2]) 3 4]
[1 2 3 4]

=> [#*[1 2] 3 4]
[1 2 3 4]

提供位置参数

=> (defn f [a b c d] [d c b a])
=> (f 1 2 3 4)
[4 3 2 1]
=> (f #*[1 2 3 4])
[4 3 2 1]

解包在各种上下文中都是允许的,并且可以在一个表达式中解包多次(PEP 3132、PEP 448)。

=>  (setv [a #* b c] [1 2 3 4 5])
=>  [a b c]
[1 [2 3 4] 5]
=> [#* [1 2] #* [3 4]]
[1 2 3 4]

unpack-mapping 取消引用并映射(映射解包)

用于在宏展开时解包映射(如哈希表),符号: unpack-mapping用#** 

=> (defn f [a b c d] [d c b a])
=> (f 1 2  #** {"c" 3 "d" 4})
[4 3 2 1]

当然解包在各种上下文中都是允许的,并且可以在一个表达式中解包多次。 

=> {#** {1 2} #** {3 4}}
{1 2  3 4}
=> (f #* [1] #* [2] #** {"c" 3} #** {"d" 4})
[4 3 2 1]

非形式句法元素 ¶

Shebang 佘邦 第一行


如果 Hy 程序以 #! 开头,则 Hy 假定第一行是 shebang 行并忽略它。由您的操作系统来做一些更有趣的事情。


Shebangs 不是真正的 Hy 语法,因此 hy.read-many 只有在启用其选项 skip_shebang 时才允许使用它们。

Whitespace 空白 ¶

Hy has lax whitespace rules less similar to Python's than to those of most other programming languages. Whitespace can separate forms (e.g., a b is two forms whereas ab is one) and it can occur inside some forms (like string literals), but it's otherwise ignored by the reader, producing no models.
Hy 具有宽松的空格规则,与 Python 的规则不同,与大多数其他编程语言的规则相似。空格可以分隔形式(例如, a b 是两种形式,而 ab 是一种形式),它可以出现在某些形式(如字符串文字)中,但会忽略它,从而不会产生任何意义。


读取器认可的 ASCII 空格字符: U+0009(水平制表符)、U+000A(换行符)、U+000B(垂直制表符)、U+000C(表单换向)、U+000D(回车符)和 U+0020(空格)。非 ASCII 空格字符(如 U+2009 (THIN SPACE))被视为任何其他字符。所以,可以在变量名称中使用那些种类繁多的空格字符,尽管平时并没有多大用处。

Comments 注释 ¶

注释以分号 ( ; ) 开头,一直持续到行尾。


没有 C 样式的多行注释 /* … */但您可以将 discard 前缀或字符串文字用于类似目的。

Discard prefix 丢弃前缀 ¶

​与Clojure一样,Hy支持可扩展数据表示丢弃前缀#_,这有点像一个结构感知注释。当程序遇到#_时,它会阅读并放弃后面部分。因此#_就像;除了读卡器宏仍在执行,并且在下一个表单结束后而不是在下一行开始时恢复正常解析:[dilly#_ and krunk]等效于[dilly-krunk',而[dilly;and krunk]仅等效于[dolly.由;指示的注释可以嵌套在由#_丢弃的表单中,但#_在由;表示的注释中没有特殊含义。
 

Identifiers 标识符 ¶

Identifiers are a broad class of syntax in Hy, comprising not only variable names, but any nonempty sequence of characters that aren't ASCII whitespace nor one of the following: ()[]{};"'`~. The reader will attempt to read an identifier as each of the following types, in the given order:
标识符是 Hy 中的一大类语法,不仅包括变量名称,还包括任何非 ASCII 空格或以下字符之一的非空字符序列: ()[]{};"'`~ .读取器将尝试按给定顺序读取以下每种类型的标识符:

  1. a numeric literal 数字文字

  2. a keyword 关键字

  3. a dotted identifier 虚线标识符

  4. a symbol 一个符号

Numeric literals 数字文字 ¶


Hy 支持 Python 的所有数字文字语法,从而生成 IntegerFloatComplex 。Hy 还提供了一些扩展:

  • 逗号 ( , ) 可以像下划线 ( _ ) 一样用于分隔数字而不改变结果。因此, 10_000_000_000 也可以写成 10,000,000,000 .Hy 对分隔符的位置也比 Python 更宽容:几个分隔符可能在一行中,它们可能在所有数字之后、 .e 、或 j 之后,甚至在基数前缀内。第一个数字之前的分隔符仍然被禁止,因为例如是 _1 合法的 Python 变量名称,因此它是 Hy 中的符号而不是整数。

  • ‘整数可以以前导零开头,即使没有像 . 0x 前导零不会像在 C 中那样自动导致以八进制解释文本。对于八进制,请使用前缀 0o ,如在 Python 中一样。

  • NaNInf-Inf 被理解为字面意思。每个都会产生一个 Float .他们是区分大小写的,与数字文字( 1E20XFF5J 等)中字母的其他用法不同。

  • Hy 允许构造函数理解的 complex 复数文字,例如 5+4j 。(这也是合法的 Python,但 Hy 将其读取为单个 Complex ,并且不支持中缀加法或减法,而 Python 将其解析为加法表达式。

class hy.models.Integer(number, *args, **kwargs)
表示文本整数 ( int )。

class hy.models.Float(num, *args, **kwargs)
表示文字浮点实数 ( float )。

class hy.models.Complex(real, imag=0, *args, **kwargs)
表示文字浮点复数 ( complex )。

Keywords 关键词 ¶


以冒号 ( : ) 开头的标识符(如 :foo )是 Keyword


文字关键字最常用于非宏调用表达式中的特殊处理:它们设置关键字参数,而不是作为值传入。例如, (f :foo 3) 调用参数 foo 设置为 3 的函数 f 。关键字在编译时也会被破坏。若要防止在表达式中专门处理文本关键字,可以 quote 将关键字用作另一个关键字参数的值,如 (f :foo :bar) 中所示。


否则,关键字是简单的模型对象,可以自行计算。其他 Lisp 的用户应该注意,使用字符串通常比使用关键字更好,因为 Python 的其余部分在其它 Lisp 使用关键字的情况下使用字符串。特别是,字符串通常比关键字更适合作为字典的键。请注意, (dict :a 1 :b 2) 它等效于 {"a" 1 "b" 2} ,这与 {:a 1 :b 2} 不同。


空关键字 : 在语法上是合法的,但由于 Python 的限制,您无法使用空关键字参数编译函数调用。因此 (foo : 3) ,必须重写以使用运行时解包,如 (foo #** {"" 3})中所示。

class hy.models.Keyword(value, from_parser=False)
表示关键字,例如 :foo

Variables: 变量:

name -- 关键字的字符串内容,不包括前导 : .不进行任何调整。

__bool__() __bool__() ¶

空关键字 : 为 false。所有其他的都是真的。

__call__(data, default=<object object>)
__call__(data, default=<object object>) ¶

Get the element of data named (hy.mangle self.name). Thus, (:foo bar) is equivalent to (get bar "foo") (which is different from (get bar :foo); dictionary keys are typically strings, not hy.models.Keyword objects).
获取 named (hy.mangle self.name)data 元素。因此, (:foo bar) 等价于 (get bar "foo") (这与 (get bar :foo) 字典键通常是字符串,而不是 hy.models.Keyword 对象不同)。

The optional second parameter is a default value; if provided, any KeyError from get will be caught, and the default returned instead.
可选的第二个参数是默认值;如果提供,则将捕获任何 KeyError FROM get ,并返回默认值。

Dotted identifiers 虚线标识符 ¶


虚线标识符因其使用点字符 . 而得名,也称为句点或句号。它们没有自己的模型类型,因为它们实际上是表达式的语法糖。语法 like foo.bar.baz 等价于 (. foo bar baz) 。一般规则是,虚线标识符看起来像两个或多个符号(本身不包含任何点),由单个点分隔。结果是一个表达式,其中符号 . 作为其第一个元素,组成符号作为其余元素。

A dotted identifier may also begin with one or more dots, as in .foo.bar or ..foo.bar, in which case the resulting expression has the appropriate head (. or .. or whatever) and the symbol None as the following element. Thus, ..foo.bar is equivalent to (.. None foo bar). In the leading-dot case, you may also use only one constitutent symbol. Thus, .foo is a legal dotted identifier, and equivalent to (. None foo).
虚线标识符也可以以一个或多个点开头,如 .foo.bar..foo.bar ,在这种情况下,生成的表达式具有适当的头部( ... 或其他)和 None 符号作为以下元素。因此, ..foo.bar 等价于 (.. None foo bar) 。在前导点的情况下,您也可以只使用一个构成符号。因此, .foo 是一个合法的虚线标识符,并等效于 (. None foo)

See the dot macro for what these expressions typically compile to. See also the special behavior for expressions that begin with a dotted identifier that itself begins with a dot. Note that Hy provides definitions of . and ... by default, but not .., ...., ....., etc., so ..foo.bar won't do anything useful by default outside of macros that treat it specially, like import.
请参阅 dot 宏,了解这些表达式通常编译到什么。另请参阅以虚线标识符开头的表达式的特殊行为,而该标识符本身以点开头。请注意,Hy 默认提供 . and ... 的定义,但不 .. 提供 、 ......... 等,因此 ..foo.bar 在专门处理它的宏之外,默认情况下不会做任何有用的事情,比如 import .

Symbols 符号 ¶

Symbols are the catch-all category of identifiers. In most contexts, symbols are compiled to Python variable names, after being mangled. You can create symbol objects with the quote operator or by calling the Symbol constructor (thus, Symbol plays a role similar to the intern function in other Lisps). Some example symbols are hello, +++, 3fiddy, $40, just✈wrong, and 🦑.
符号是标识符的包罗万象的类别。在大多数情况下,符号在被篡改后被编译为 Python 变量名称。您可以使用 quote 运算符或调用 Symbol 构造函数来创建符号对象(因此, Symbol 在其他 Lisp 中扮演类似于该 intern 函数的角色)。一些示例符号是 hello+++3fiddy$40just✈wrong🦑

仅当符号中的每个字符都是点时,才允许在符号中使用点。因此, a. 和a..b 既不是虚线标识符也不是符号;它们是语法错误。

As a special case, the symbol ... compiles to the Ellipsis object, as in Python.
作为一种特殊情况,符号 ... 编译到 Ellipsis 对象中,就像在 Python 中一样。

class hy.models.Symbol(s, from_parser=False)
 

Represents a symbol. 表示符号。

Symbol objects behave like strings under operations like get, len(), and bool; in particular, (bool (hy.models.Symbol "False")) is true. Use hy.eval to evaluate a symbol.
符号对象的行为类似于 getlen()bool 等运算下的字符串;特别是, (bool (hy.models.Symbol "False")) 是真的。用于 hy.eval 计算符号。

Mangling 缺少 ¶

Since the rules for Hy symbols and keywords are much more permissive than the rules for Python identifiers, Hy uses a mangling algorithm to convert its own names to Python-legal names. The steps are as follows:
由于 Hy 符号和关键字的规则比 Python 标识符的规则宽松得多,因此 Hy 使用一种篡改算法将自己的名称转换为 Python 合法名称。步骤如下:

  1. Remove any leading underscores. Underscores are typically the ASCII underscore _, but they may also be any Unicode character that normalizes (according to NFKC) to _. Leading underscores have special significance in Python, and Python normalizes all Unicode before this test, so we'll process the remainder of the name and then add the leading underscores back onto the final mangled name.
    删除所有前导下划线。下划线通常是 ASCII 下划线 _ ,但它们也可以是任何规范化(根据 NFKC)为 _ 的 Unicode 字符。前导下划线在 Python 中具有特殊意义,Python 在此测试之前对所有 Unicode 进行规范化,因此我们将处理名称的其余部分,然后将前导下划线添加回最终的 mangled 名称中。

  2. Convert ASCII hyphens (-) to underscores (_). Thus, foo-bar becomes foo_bar. If the name at this step starts with a hyphen, this first hyphen is not converted, so that we don't introduce a new leading underscore into the name. Thus --has-dashes? becomes -_has_dashes? at this step.
    将 ASCII 连字符 ( - ) 转换为下划线 ( _ )。因此, foo-bar 成为 foo_bar .如果此步骤中的名称以连字符开头,则不会转换第一个连字符,因此我们不会在名称中引入新的前导下划线。因此 --has-dashes? 成为 -_has_dashes? 这一步。

  3. If the name still isn't Python-legal, make the following changes. A name could be Python-illegal because it contains a character that's never legal in a Python name or it contains a character that's illegal in that position.
    如果名称仍不是 Python 合法名称,请进行以下更改。一个名称可能是 Python 非法的,因为它包含一个在 Python 名称中从不合法的字符,或者它包含一个在该位置是非法的字符。

    • Prepend hyx_ to the name.
      在名称前面加上 hyx_

    • Replace each illegal character with XfooX, where foo is the Unicode character name in lowercase, with spaces replaced by underscores and hyphens replaced by H. Replace leading hyphens and X itself the same way. If the character doesn't have a name, use U followed by its code point in lowercase hexadecimal.
      将每个非法字符替换为 XfooX ,其中 foo Unicode 字符名称为小写,空格替换为下划线,连字符替换为 H 。以同样的方式替换前导连字符和 X 本身。如果字符没有名称,请使用 U 后跟小写十六进制的代码点。

    Thus, green☘ becomes hyx_greenXshamrockX and -_has_dashes becomes hyx_XhyphenHminusX_has_dashes.
    因此, green☘ 成为 hyx_greenXshamrockX 并成为 -_has_dashes hyx_XhyphenHminusX_has_dashes .

  4. Take any leading underscores removed in the first step, transliterate them to ASCII, and add them back to the mangled name. Thus, __green☘ becomes __hyx_greenXshamrockX.
    将第一步中移除的任何前导下划线,音译为 ASCII,然后将它们添加回被破坏的名称中。因此, __green☘ 成为 __hyx_greenXshamrockX .

  5. Finally, normalize any leftover non-ASCII characters. The result may still not be ASCII (e.g., α is already Python-legal and normalized, so it passes through the whole mangling procedure unchanged), but it is now guaranteed that any names are equal as strings if and only if they refer to the same Python identifier.
    最后,规范化任何剩余的非 ASCII 字符。结果可能仍然不是 ASCII(例如, α 已经是 Python 合法的和规范化的,因此它在整个 mangling 过程中保持不变),但现在可以保证任何名称都等于字符串,当且仅当它们引用相同的 Python 标识符时。

You can invoke the mangler yourself with the function hy.mangle, and try to undo this (perhaps not quite successfully) with hy.unmangle.
您可以使用函数 hy.mangle 自己调用 mangler,并尝试使用 hy.unmangle 撤消此操作(可能不太成功)。

Mangling isn't something you should have to think about often, but you may see mangled names in error messages, the output of hy2py, etc. A catch to be aware of is that mangling, as well as the inverse "unmangling" operation offered by hy.unmangle, isn't one-to-one. Two different symbols, like foo-bar and foo_bar, can mangle to the same string and hence compile to the same Python variable.
改动不是你应该经常考虑的事情,但你可能会在错误消息、输出等 hy2py 中看到被改动的名称。需要注意的一个问题是,mangling 以及 提供 hy.unmangle 的反向“unmangling”操作不是一对一的。两个不同的符号,如 foo-barfoo_bar ,可以修改为同一个字符串,从而编译为同一个 Python 变量。

String literals 字符串文字 ¶

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 Additional sugar). Python's so-called triple-quoted strings (e.g., '''hello''' and """hello""") aren't supported, either. However, in Hy, unlike Python, any string literal can contain newlines; furthermore, Hy has bracket strings. For consistency with Python's triple-quoted strings, all literal newlines in literal strings are read as in "\n" (U+000A, line feed) regardless of the newline style in the actual code.
Hy 允许使用双引号字符串(例如 "hello" ),但不允许像 Python 那样使用单引号字符串。单引号字符 ' 是用来防止对表单的计算的,(例如, '(+ 1 1) ),就像在大多数Lisps中一样(参见额外的糖)。Python 所谓的三引号字符串(例如, '''hello'''"""hello""" )也不支持。但是,在 Hy 中,与 Python 不同,任何字符串文本都可以包含换行符;此外,Hy 有括号字符串。为了与 Python 的三引号字符串保持一致,无论实际代码中的换行符样式如何,文本字符串中的所有文字换行符都读作 in "\n" (U+000A,换行符)。

String literals support a variety of backslash escapes. 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".
字符串文本支持各种反斜杠转义。无法识别的转义序列是语法错误。要创建一个从字面上解释所有反斜杠的“原始字符串”,请在字符串前面加上 r ,如 中 r"slash\not" 所示。

By default, all string literals are regarded as sequences of Unicode characters. The result is the model type String. You may prefix a string literal with b to treat it as a sequence of bytes, producing Bytes instead.
默认情况下,所有字符串文本都被视为 Unicode 字符序列。结果是模型类型 String 。您可以在字符串文本前面加上 with b 以将其视为字节序列,而是生成 Bytes

Unlike Python, Hy only recognizes string prefixes (r, b, and f) in lowercase, and doesn't allow the no-op prefix u.
与 Python 不同,Hy 只识别小写的字符串前缀( rbf ),不允许使用 no-op 前缀 u

F-strings are a string-like compound construct documented further below.
F 弦是一种类似弦的复合结构,下面将进一步记录。

class hy.models.String(s=None, brackets=None)
class hy.models.String(s=None, brackets=None) ¶

Represents a literal string (str).
表示文本字符串 ( str )。

Variables: 变量:

brackets -- The custom delimiter used by the bracket string that parsed to this object, or None if it wasn't a bracket string. The outer square brackets and # aren't included, so the brackets attribute of the literal #[[hello]] is the empty string.
括号 -- 分析为此对象的括号字符串使用的自定义分隔符,或者 None 如果它不是括号字符串。外方括号 和 # 不包括在内,因此文本的 brackets 属性 #[[hello]] 是空字符串。

class hy.models.Bytes

Represents a literal bytestring (bytes).
表示文本字节串 ( bytes )。

Bracket strings 括号字符串 ¶

Hy supports an alternative form of string literal called a "bracket string" similar to Lua's long brackets. Bracket strings have customizable delimiters, like the here-documents of other languages. A bracket string begins with #[FOO[ and ends with ]FOO], where FOO is any string not containing [ or ], including the empty string. (If FOO is exactly f or begins with f-, the bracket string is interpreted as an f-string.) For example:
Hy 支持另一种形式的字符串文字,称为“括号字符串”,类似于 Lua 的长括号。括号字符串具有可自定义的分隔符,就像其他语言的 here-documents 一样。括号字符串以 开头 #[FOO[ 以 结尾,其中 FOO 不包含 [] 的任何字符串,包括空 ]FOO] 字符串。(如果 FOO 正好 f 或以 f- 开头,则括号字符串被解释为 f 字符串。例如:

(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.
括号字符串始终是原始 Unicode 字符串,不允许使用 r or b 前缀。

A bracket string can contain newlines, but if it begins with one, the newline is removed, so you can begin the content of a bracket string on the line following the opening delimiter with no effect on the content. Any leading newlines past the first are preserved.
括号字符串可以包含换行符,但如果以换行符开头,则换行符将被删除,因此您可以在开始分隔符后面的行上开始括号字符串的内容,而不会影响内容。任何超过第一个的前导换行符都将被保留。

Sequential forms 顺序表单 ¶

Sequential forms (Sequence) are nested forms comprising any number of other forms, in a defined order.
顺序形式 ( Sequence ) 是嵌套形式,以定义的顺序包含任意数量的其他形式。

class hy.models.Sequence(iterable=(), /)
class hy.models.Sequence(iterable=(), /) ¶

An abstract base class for sequence-like forms. Sequence models can be operated on like tuples: you can iterate over them, index into them, and append them with +, but you can't add, remove, or replace elements. Appending a sequence to another iterable object reuses the class of the left-hand-side object, which is useful when e.g. you want to concatenate models in a macro.
用于类似序列的表单的抽象基类。序列模型可以像元组一样进行操作:您可以迭代它们,为它们编制索引,并用 追加它们 + ,但不能添加、删除或替换元素。将序列追加到另一个可迭代对象会重用左侧对象的类,这在例如想要连接宏中的模型时很有用。

When you're recursively descending through a tree of models, testing a model with (isinstance x hy.models.Sequence) is useful for deciding whether to iterate over x. You can also use the Hyrule function coll? for this purpose.
当您以递归方式在模型树中下降时,测试模型 (isinstance x hy.models.Sequence) 对于决定是否迭代 x 很有用。您也可以将 Hyrule 函数 coll? 用于此目的。

Expressions 表达式 ¶

Expressions (Expression) are denoted by parentheses: ( … ). The compiler evaluates expressions by checking the first element, called the head.
表达式 ( Expression ) 用括号表示: ( … ) 。编译器通过检查第一个元素(称为 head)来计算表达式。

  • If the head is a symbol, and the symbol is the name of a currently defined macro, the macro is called.
    如果 head 是符号,并且符号是当前定义的宏的名称,则调用该宏。

    • Exception: if the symbol is also the name of a function in hy.pyops, and one of the arguments is an unpack-iterable form, the pyops function is called instead of the macro. This makes reasonable-looking expressions work that would otherwise fail. For example, (+ #* summands) is understood as (hy.pyops.+ #* summands), because Python provides no way to sum a list of unknown length with a real addition expression.
      例外:如果符号也是 中的 hy.pyops 函数名称,并且其中一个参数是 unpack-iterable 表单,则调用该 pyops 函数而不是宏。这使得看起来合理的表达式起作用,否则会失败。例如, (+ #* summands) 被理解为 (hy.pyops.+ #* summands) ,因为 Python 没有提供使用实加表达式对未知长度的列表求和的方法。

  • If the head is itself an expression of the form (. None …) (typically produced with a dotted identifier like .add), it's used to construct a method call with the element after None as the object: thus, (.add my-set 5) is equivalent to ((. my-set add) 5), which becomes my_set.add(5) in Python.
    如果 head 本身是表单 (. None …) 的表达式(通常使用虚线标识符生成,例如 .add ),它用于构造一个方法调用,其中 after None 的元素作为对象:因此, (.add my-set 5) 等价于 ((. my-set add) 5) ,在 Python 中变为 my_set.add(5)

    • Exception: expressions like ((. hy R module-name macro-name) …), or equivalently (hy.R.module-name.macro-name …), get special treatment. They require the module module-name and call its macro macro-name, so (hy.R.foo.bar 1) is equivalent to (require foo) (foo.bar 1), but without bringing foo or foo.bar into scope. Thus hy.R is convenient syntactic sugar for macros you'll only call once in a file, or for macros that you want to appear in the expansion of other macros without having to call require in the expansion. As with hy.I, dots in the module name must be replaced with slashes.
      例外:像 ((. hy R module-name macro-name) …) 或等效的 (hy.R.module-name.macro-name …) 表达式会得到特殊处理。它们 require 调用模块 module-name 并调用其宏 macro-name ,所以 (hy.R.foo.bar 1) 等价于 (require foo) (foo.bar 1) ,但没有引入 foofoo.bar 进入作用域。因此 hy.R ,对于您只在文件中调用一次的宏,或者您希望出现在其他宏的扩展中而不必调用 require 扩展的宏,这是方便的语法糖。与 一样 hy.I ,模块名称中的点必须替换为斜杠。

  • Otherwise, the expression is compiled into a Python-level call, with the head being the calling object. (So, you can call a function that has the same name as a macro with an expression like ((do setv) …).) The remaining forms are understood as arguments. Use unpack-iterable or unpack-mapping to break up data structures into individual arguments at runtime.
    否则,表达式将编译为 Python 级别的调用,其中 head 是调用对象。(因此,您可以调用与宏同名的函数,其表达式为 ((do setv) …) 。其余形式被理解为参数。在运行时使用 unpack-iterableunpack-mapping 将数据结构分解为单独的参数。

The empty expression () is legal at the reader level, but has no inherent meaning. Trying to compile it is an error. For the empty tuple, use #().
空表达 () 在读者层面上是合法的,但没有内在含义。尝试编译它是一个错误。对于空元组,请使用 #() .

class hy.models.Expression(iterable=(), /)
class hy.models.Expression(iterable=(), /) ¶

Represents a parenthesized Hy expression.
表示带括号的 Hy 表达式。

List, tuple, and set literals
列表、元组和设置文本 ¶

  • Literal lists (List) are denoted by [ … ].
    文字 list s ( List ) 用 表示 [ … ]

  • Literal tuples (Tuple) are denoted by #( … ).
    文字 tuple s ( Tuple ) 用 表示 #( … )

  • Literal sets (Set) are denoted by #{ … }.
    文字 set s ( Set ) 用 表示 #{ … }

class hy.models.List(iterable=(), /)
class hy.models.List(iterable=(), /) ¶

Represents a literal list.
表示文本 list

Many macros use this model type specially, for something other than defining a list. For example, defn expects its function parameters as a square-bracket-delimited list, and for expects a list of iteration clauses.
许多宏专门使用此模型类型,用于定义 list .例如, defn 期望其函数参数为方括号分隔的列表,并 for 期望迭代子句列表。

class hy.models.Tuple(iterable=(), /)
class hy.models.Tuple(iterable=(), /) ¶

Represents a literal tuple.
表示文本 tuple

class hy.models.Set(iterable=(), /)
class hy.models.Set(iterable=(), /) ¶

Represents a literal set. Unlike actual sets, the model retains duplicates and the order of elements.
表示文本 set 。与实际集合不同,该模型保留了重复项和元素的顺序。

Dictionary literals 字典文字 ¶

Literal dictionaries (dict, Dict) are denoted by { … }. Even-numbered child forms (counting the first as 0) become the keys whereas odd-numbered child forms become the values. For example, {"a" 1 "b" 2} produces a dictionary mapping "a" to 1 and "b" to 2. Trying to compile a Dict with an odd number of child models is an error.
文字词典 ( dictDict ) 用 { … } 表示。偶数子表单(第一个计为 0)成为键,而奇数子表单成为值。例如, {"a" 1 "b" 2} 生成 "a" 一个映射到 1"b"2 字典映射。尝试使用奇数个子模型编译一个 Dict 是错误的。

As in Python, calling dict with keyword arguments is often more convenient than using a literal dictionary.
与 Python 一样,使用关键字参数进行调用 dict 通常比使用文字字典更方便。

class hy.models.Dict(iterable=(), /)
class hy.models.Dict(iterable=(), /) ¶

Represents a literal dict. keys, values, and items methods are provided, each returning a list, although this model type does none of the normalization of a real dict. In the case of an odd number of child models, keys returns the last child whereas values and items ignore it.
表示文本 dictkeys values 、 和 items 方法都提供了,每个方法都返回一个列表,尽管此模型类型不执行实 dict 数 .如果子模型为奇数, keys 则返回最后一个子模型并 values items 忽略它。

Format strings 格式化字符串 ¶

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 FString, Hy f-strings work much like Python f-strings except that the embedded code is in Hy rather than Python.
格式化字符串(或“f-string”或“格式化字符串文本”)是带有嵌入代码的字符串文本,可能附带格式化命令。结果是 FString Hy f-strings 的工作方式与 Python f 字符串非常相似,只是嵌入的代码是 Hy 而不是 Python。

(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:
由于 =!: 是 Hy 中的标识符字符,因此 Hy 通过分析一个表单来决定替换字段中的代码的结束位置(以及任何调试 = 、转换说明符或格式说明符的开始位置)。您可以像往常一样将 do 多个表单合并为一个。可能需要空格来终止表单:

(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.
与 Python 不同,转换和格式说明符之间允许空格。

Also unlike Python, comments and backslashes are allowed in replacement fields. The same reader is used for the form to be evaluated as for elsewhere in the language. Thus e.g. f"{"a"}" is legal, and equivalent to "a".
此外,与 Python 不同的是,替换字段中允许注释和反斜杠。与语言中的其他地方一样,要评估的表单使用相同的阅读器。因此,例如 f"{"a"}" 是合法的,并且等价于 "a"

class hy.models.FString(s=None, brackets=None)
class hy.models.FString(s=None, brackets=None) ¶

Represents a format string as an iterable collection of hy.models.String and hy.models.FComponent. The design mimics ast.JoinedStr.
将格式字符串表示为 hy.models.Stringhy.models.FComponent 的可迭代集合。该设计模仿 ast.JoinedStr .

Variables: 变量:

brackets -- As in hy.models.String.
括号 -- 如 。 hy.models.String

class hy.models.FComponent(s=None, conversion=None)
class hy.models.FComponent(s=None, conversion=None) ¶

An analog of ast.FormattedValue. The first node in the contained sequence is the value being formatted. The rest of the sequence contains the nodes in the format spec (if any).
ast.FormattedValue 类似物。包含的序列中的第一个节点是要格式化的值。序列的其余部分包含格式规范(如果有)中的节点。

Additional sugar 额外加糖 ¶

Syntactic sugar is available to construct two-item expressions with certain heads. When the sugary characters are encountered by the reader, a new expression is created with the corresponding macro name as the first element and the next parsed form as the second. No parentheses are required. Thus, since ' is short for quote, 'FORM is read as (quote FORM). Whitespace is allowed, as in ' FORM. This is all resolved at the reader level, so the model that gets produced is the same whether you take your code with sugar or without.
语法糖可用于构造具有某些头的双项表达式。当读者遇到含糖字符时,将创建一个新表达式,其中相应的宏名称作为第一个元素,下一个解析的形式作为第二个元素。不需要括号。因此,由于 ' 是 的 quote 缩写, 'FORM 因此读作 (quote FORM) 。允许使用空格,如 ' FORM .这一切都在读者级别得到解决,因此无论您使用糖或不糖的代码,生成的模型都是相同的。

Macro 宏观

Syntax 语法

quote

'FORM

quasiquote

`FORM

unquote

~FORM

unquote-splice

~@FORM

unpack-iterable

#* FORM

unpack-mapping

#** FORM

Reader macros 阅读器宏 ¶

A hash (#) followed by a symbol invokes the reader macro named by the symbol. (Trying to call an undefined reader macro is a syntax error.) Parsing of the remaining source code is under control of the reader macro until it returns.
哈希 ( # ) 后跟一个符号将调用由该符号命名的读取器宏。(尝试调用未定义的读取器宏是语法错误。其余源代码的解析由 reader 宏控制,直到它返回。

;