【问题标题】:Why are calls to `defmacro` evaluating to None?为什么对“defmacro”的调用评估为无?
【发布时间】:2021-03-14 07:44:36
【问题描述】:

我正在编写以下代码:

(require [hy.contrib.walk [let]])


(defn maybe? [command-text]
  (let [splitted (.split command-text " ")]
    (= (get splitted 0) "maybe")))


(defn if? [command-text]
  (let [splitted (.split command-text " ")]
    (+ (get splitted 0) "if")))

...直到我意识到我在做一些重复的事情,所以我想把模式分解出来:

(import [hy [HySymbol]])


(defmacro command-dispatcher [command-type]
  `(defn ~(HySymbol (+ command-type "?")) [command-text]
     (let [splitted (.split command-text " ")]
       (= (get splitted 0) ~command-type))))

但是,如果我在 HyREPL 中评估 (command-dispatcher "maybe"),我会得到 None

=> (command-dispatcher "maybe")
def is_maybe(command_text):
    _hyx_letXUffffX3 = {}
    _hyx_letXUffffX3['splitted'] = command_text.split(' ')
    return _hyx_letXUffffX3['splitted'][0] == 'maybe'


None

这很奇怪,因为宏应该返回HyExpression,而不是None。我错过了什么?

【问题讨论】:

    标签: macros hy


    【解决方案1】:

    您的宏不会返回任何内容,但会定义一个函数,正如您在此处看到的那样

    (assert (not (in "is_maybe" (dir))))
    (command-dispatcher "maybe")
    (assert (in "is_maybe" (dir)))
    

    您的代码中的一个问题是您正在使用let,根据documentation,它不再可用,这是一种使用setv 重写它的可能方法:

    (defmacro command-dispatcher [command-type]
      `(defn ~(HySymbol (+ command-type "?")) [command-text]
           (setv splitted (.split command-text " "))
           (= (get splitted 0) ~command-type)))
    

    然后您可以使用is_maybe(或maybe?,这是语法糖)调用此函数,例如。

    (command-dispatcher "maybe")
    
    (print (maybe? "foo"))
    (print (maybe? "maybe foo"))
    

    将打印

    False
    True
    

    【讨论】:

    • 所以,command-dispatcher 是一个有效的函数,它只是将符号绑定到生成的函数,并且没有返回任何有用的信息。然而,这种行为与其他 Lisp 的行为不同。 AFAIK,他们的宏实际上返回一段代码,而不是产生绑定效果。
    • let 已在 hy.contrib.walk 中重新实现。
    • @Kodiologist you are right,我在测试我的代码时忘记导入它,感谢您的精确。
    猜你喜欢
    • 1970-01-01
    • 2014-05-19
    • 2019-05-24
    • 2015-03-15
    • 2022-01-25
    • 1970-01-01
    • 2014-06-17
    • 1970-01-01
    • 2017-04-28
    相关资源
    最近更新 更多