gpt4 book ai didi

macros - lisp:何时使用函数与宏

转载 作者:行者123 更新时间:2023-12-04 11:55:36 25 4
gpt4 key购买 nike

在我不断学习 lisp 的过程中,我遇到了一个概念问题。这有点类似于问题 here ,但也许从主题上来说,我的问题是抽象的层次。

通常,何时应该创建宏与函数?在我看来,也许天真地认为,在极少数情况下您必须创建宏而不是函数,并且在大多数剩余情况下,函数通常就足够了。在这些剩余情况中,宏的主要附加值(value)似乎是语法清晰。如果是这样的话,那么看起来不仅选择使用宏的决定,而且它们的结构设计可能从根本上对单个程序员来说是特殊的。

这是错的吗?是否有一般情况概述何时使用宏而不是函数?语言需要宏的情况通常很少,我说得对吗?最后,是否存在宏所期望的通用句法形式,或者它们通常被程序员用作速记?

最佳答案

是的,第一条规则是:不要在函数可以使用的地方使用宏。

有些事情你不能用函数做,例如代码的条件评估。其他人变得相当笨拙。

一般来说,我知道宏的三个反复出现的用例(这并不意味着没有其他用例):

  • 定义表格(例如 defundefmacrodefine-frobble-twiddle)

    这些通常需要获取一些代码片段,将其包装(例如以 lamdba 形式),并将其注册到某个地方,甚至可能是多个地方。用户(程序员)应该只关心代码片段。因此,这主要是关于删除样板。此外,宏可以处理主体,例如。 G。注册文档字符串,处理声明等。

    示例:假设您正在编写一种事件迷你框架。您的事件处理程序是纯函数,它们接受一些输入并产生效果声明(想想来自 Clojure 世界的重新框架)。您希望这些函数是普通的命名函数,以便您可以使用通常的测试框架对其进行测试,但也可以将它们注册到您的事件循环机制的查找表中。您可能想要 define-handler 之类的东西宏:
    (defvar *handlers* (make-hash-table)) ; internal for the framework

    (defmacro define-handler (&whole whole name lambda-list &body body)
    `(progn (defun ,@(rest whole))
    (setf (gethash ,name *handlers*)
    (lambda ,lambda-list ,@body)))) ; could also be #',name
  • 控制结构(例如 casecondswitchsome->)

    这些使用条件评估和方便的表达式重新排列。
  • With-样式包装器

    这是一个成语提供unwind-protect一些任意资源的功能。与一般 with 的区别构造(如在 Clojure 中)是资源类型可以是任何东西,您不必用 Closable 之类的东西来具体化它。界面。

    例子:
    (defmacro with-foo-bar-0 (&body body)
    (let ((foo-bar (gensym "FOO-BAR")))
    `(let (,foo-bar))
    (shiftf ,foo-bar (aref (gethash :foo *buzz*) 0) 0)
    (unwind-protect (progn ,@body)
    (setf (aref (gethash :foo *buzz*) 0) ,foo-bar)))))

    这会将嵌套数据结构中的某些内容设置为 0,并确保它在任何(甚至是非本地)退出时重置为之前的值。
  • 关于macros - lisp:何时使用函数与宏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59244410/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com