[英]Scheme: macros or higher order functions for code duplication?
我想得到一个 function 的结果,它调用一个 shell 命令并返回一个字符串。 我正在使用球拍,这是我的第一次尝试:
(define (run-function)
(let*
([stdout (some-function)]
[output (process-string stdout)])
;; many more lines...
output))
它似乎工作得很好,但假设我想为许多其他 shell 命令编写类似于run-function
。
为了避免代码重复,我可以像这样定义一个更通用的 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)]))
这也将具有允许更通用语法的优点,例如我可以轻松更改宏,以便它需要尽可能多的参数(命令),但我确信可以通过编写更高的顺序来复制相同的行为function 更明智。
问:与宏相比,编写高阶 function 的优缺点是什么? 两者之间有明显的赢家吗?
我同意@MLavrentyev 所说的话,“如果可以的话,请使用 function”。
球拍风格指南还说:
尽可能定义函数,或者在函数可以使用时不要引入宏。
但为什么? 一个原因是,如果您将shell
写为 function,您可以将shell
传递给其他函数。 您可以通过标识符宏功能对宏执行相同的操作,但这样做要困难得多(无论如何您最终都会有效地创建 function)。
另一个原因是使用宏会使编译后的代码比使用函数大。 这是因为宏在编译时被扩展,然后扩展的代码被编译(在 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))
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.