【问题标题】:Scheme: macros or higher order functions for code duplication?方案:用于代码重复的宏或高阶函数?
【发布时间】:2021-02-25 21:31:21
【问题描述】:

我想获得一个调用 shell 命令并返回字符串的函数的结果。 我正在使用球拍,这是我的第一次尝试:

(define (run-function)
  (let*
    ([stdout (some-function)]
     [output (process-string stdout)])
  ;; many more lines...
  output))

它似乎工作得很好,但假设我想为许多其他 shell 命令编写类似于run-function 的函数。

为避免代码重复,我可以定义一个更通用的函数,如下所示:

(define (shell cmd)
  (let*
    ([stdout (cmd)]
     [output (process-string stdout)])
  ;; many more lines...
  output))

然后调用例如(shell ls)(shell pwd)

另一种方法是使用简单的宏:

(define-syntax shell
  (syntax-rules ()
    [(shell cmd)
     (let*
       ([stdout (cmd)]
        [output (process-string stdout)])
       ;; many more lines...
       output)]))

这还具有允许更通用语法的优点,例如,我可以轻松更改宏,以便它需要尽可能多的参数(命令),但我确信可以通过编写来复制相同的行为高阶函数更合理。

问。编写高阶函数与宏的优缺点是什么?两者之间有明显的赢家吗?

【问题讨论】:

  • 我认为一个好的经验法则是尽可能地使用函数,并且只有当你绝对需要宏时(例如,为了避免评估)你才使用它。不是一个完美的规则(宏有利于简化语法),但重点是:尽可能使用函数。
  • @MLavrentyev 你的评论让我终于明白为什么我们会喜欢宏:做一些非常特殊的任务,比如改变解释器的工作规则——在大多数语言中都是这样除非您准备更改解释器源代码本身,否则这是不可能的(然后您必须记住使用您的自定义解释器来运行某个脚本……复杂性会飞得很快)。

标签: macros scheme racket higher-order-functions idioms


【解决方案1】:

我同意 @MLavrentyev said 的说法,“如果可以,请使用函数”。

the Racket style guide 还说:

尽可能定义函数,或者,当函数可以使用时不要引入宏。

但是为什么呢?一个原因是如果你把shell写成一个函数,你可以把shell传递给其他函数。您可以通过identifier macro 功能对宏执行相同的操作,但这样做要困难得多(而且您最终会有效地创建一个函数)。

另一个原因是使用宏会使编译后的代码比使用函数大。这是因为宏在编译时被扩展,然后扩展的代码被编译(在 Racket BC 中为字节码,在 Racket CS 中为机器码)。所以就好像你一遍又一遍地写(let* ...)。如果您分发已编译或可执行的 Racket 程序,您不会希望大小很大。

事实上,编写宏时的一个好习惯是尽量将代码填充到函数中。而不是写:

(define-syntax-value (debug code)
  (let ([val code])
    (printf "~a evaluates to ~a\n" (quote code) val)
    val))

最好写成:

(define (debug-core expr val)
  (printf "~a evaluates to ~a\n" expr val)
  val)

(define-syntax-value (debug code)
  (debug-core (quote code) code))

【讨论】:

  • 谢谢。似乎我的资料之一,Kent Dybvig 的书 The Scheme Programming Language 可以被解释为不 100% 同意球拍风格指南。在书中的某个地方,他说:句法扩展或宏用于简化和规范程序中的重复模式,引入具有新评估规则的句法形式,并执行有助于提高程序效率的转换。 这让我觉得可以使用宏来尽量减少代码重复。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-29
  • 2020-11-19
  • 2013-04-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多