簡體   English   中英

方案:用於代碼重復的宏或高階函數?

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

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM