宏相关语法糖
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 |
|
quasiquote |
|
unquote |
|
unquote-splice |
|
unpack-iterable |
|
unpack-mapping |
|
quote 引号,是双引号下面的那个单引号'
quasiquote 反引号,是左上角波浪线下面的那个引号`
unquote 波浪线 取消引用~
unquote-splice 取消引用并展开 波浪线+@ ~@
unpck-iterable 取消引用并迭代 使用#*
unpack-mapping 取消引用并映射 #**
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]