2012-04-08 82 views
2

當我學習方案和球拍時,我發現自己一次又一次地重複這種模式。在哪裏我有一個遞歸函數,其中一些函數的參數發生了變化,但有些參數卻沒有。我構建了一個外部函數,它接受所有參數,並在其中定義一個內部函數,該函數僅接受變化的參數並在其上重複。宏以簡化遞歸函數語法

舉一個具體的例子繼承人在「小策士」

;inserts an item to the right of an element in a list 
(define (insert-to-right new old lat)  
    (define (insert-to-right lat) 
    (cond 
     [(null? lat) lat] 
     [(eq? old (car lat)) (cons old (cons new (cdr lat)))] 
     [else (cons (car lat) (insert-to-right (cdr lat)))])) 
    (insert-to-right lat)) 

上的功能鍛鍊有點基礎的情況下,是否有可能建立一個宏定義*和運營商(例如豎線)等我鍵入:

(define* (insert-to-right new old | lat)  
    (cond 
     [(null? lat) lat] 
     [(eq? old (car lat)) (cons old (cons new (cdr lat)))] 
     [else (cons (car lat) (insert-to-right (cdr lat)))])) 

,然後這將擴大到第一形式被傳遞給外部函數的所有參數,但只有垂直條後的參數被傳遞給內迴路。

回答

3

玩弄我已經建立了一個宏,我想要做什麼之後。

(define-syntax-rule 
    (define* (function-name (outer-var ...) (inner-var ...)) expr ...) 
    (define (function-name outer-var ... inner-var ...) 
    (define (function-name inner-var ...)expr ...) 
    (function-name inner-var ...))) 


(define* (insert-to-right [new old] [lat])   
    (cond 
     [(null? lat) lat] 
     [(eq? old (car lat)) (cons old (cons new (cdr lat)))] 
     [else (cons (car lat) (insert-to-right (cdr lat)))])) 

> (insert-to-right 11 3 '(1 2 3 4 5 6)) 
'(1 2 3 11 4 5 6) 

在定義*語句不使用內,外參數之間的分隔符(如我本來試圖這樣做),但把內,外參數的定義*語句爲單獨列出了我認爲是更習慣性的計劃/球拍。

8

你可以寫這樣一個宏,但你也可以只使用一個名爲令:

(define (insert-to-right new old lat) 
    (let loop ([lat lat]) 
    (cond 
     [(null? lat)   lat] 
     [(eq? old (car lat)) (cons old (cons new (cdr lat)))] 
     [else    (cons (car lat) (loop (cdr lat)))]))) 
+0

感謝Matthias。我想知道如何在沒有內部函數或命名let的情況下做到這一點。 – 2012-04-08 22:06:47

0

你不應該使用宏來做到這一點。這是一個高階函數的教科書案例;特別是,我相信你的例子可以寫成pair-fold-right from SRFI-1。未經測試的代碼(我希望這是正確的):

(define (insert-to-right new old lat) 
    (pair-fold-right (lambda (pair rest) 
        (if (eq? (car pair) old) 
         (cons (car pair) 
           (cons new rest)) 
         pair)) 
        '() 
        lat)) 

;;; Example implementation of pair-fold-right, just for one list—your Scheme system 
;;; probably has this as a library function somewhere 
(define (pair-fold-right fn init list) 
    (if (null? list) 
     init 
     (fn list (pair-fold-right fn init (cdr list))))) 
+0

謝謝Sacundim,但我只是使用插入到右側作爲示例。這個問題是關於簡化一般情況下的語法,在這種情況下,我重複使用了一些參數不變且一些參數不變的函數。 – 2012-04-10 23:04:46

+0

那麼,我的建議就是不要這樣做。宏使代碼難以閱讀和排除故障,而且確實只有幾件事情完全需要它們。例如,(a)添加不評估所有子表達式的表達式,或者(b)添加新類型的綁定表單(綁定新變量的表達式)。 – 2012-04-11 00:57:13

+0

什麼任何形式的副作用,如: (定義語法規則(增量X)(設置X(ADD1 X))!) 它可以讓你做這個經典的更加清晰: (定義(使(計數器0) (lambda()(增量!計數器)計數器)) (定義計數器1 – 2012-04-12 20:36:07