[英]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.