方案:用于代码复制的宏或高阶函数?
Scheme: macros or higher order functions for code duplication?
我想获得调用 shell 命令和 returns 字符串的函数的结果。
我正在使用球拍,这是我的第一次尝试:
(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)]))
这还有一个优点是允许使用更通用的语法,例如我可以轻松更改宏,以便它可以根据需要使用尽可能多的参数(命令),但我确信可以复制相同的行为通过更明智地编写高阶函数。
问。 pros/cons 编写高阶函数与宏有什么区别?两者之间有明显的赢家吗?
我同意 @MLavrentyev 的观点,“如果可以,请使用函数”。
Define functions when possible, Or, do not introduce macros when functions will do.
但是为什么呢?一个原因是,如果将 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))
我想获得调用 shell 命令和 returns 字符串的函数的结果。 我正在使用球拍,这是我的第一次尝试:
(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)]))
这还有一个优点是允许使用更通用的语法,例如我可以轻松更改宏,以便它可以根据需要使用尽可能多的参数(命令),但我确信可以复制相同的行为通过更明智地编写高阶函数。
问。 pros/cons 编写高阶函数与宏有什么区别?两者之间有明显的赢家吗?
我同意 @MLavrentyev
Define functions when possible, Or, do not introduce macros when functions will do.
但是为什么呢?一个原因是,如果将 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))