2012-04-08 12 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

を。それがどのI別々のリストに(私は元々実行しようとしたように)、内側と外側のパラメータ間のセパレータを使用するが、定義*ステートメントで内側と外側のパラメータを置くない定義*文の

(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) 

思考はより慣用的なScheme/Racketです。

8

あなたは、このようなマクロを書くことができますが、あなたはまた、単に名前のLET使用することができます:私は、私が欲しいものを行うマクロを構築しました遊ん後

(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

ありがとうございました。私は内部関数か名前付きletのどちらを使わなくても、どうやってそれをやり遂げることができるのだろうかと思っています。 –

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ありがとうございましたが、例としてinsert-to-rightしか使っていませんでした。問題は、いくつかのパラメータが不変であり、いくつかが不変である関数で繰り返される一般的なケースの構文を簡素化することでした。 –

+0

さて、私のアドバイスはそれだけではありません。マクロは、コードの読み込みやトラブルシューティングをより困難にします。本当に必要なものはほんのわずかです。たとえば、(a)すべての部分式を評価しない式を追加する、または(b)新しいタイプのバインディングフォーム(新しい変数をバインドする式)を追加するなどです。 –

+0

何のような副作用のいずれかの形式について:あなたはこの古典をより明確にすることができます (定義 - 構文規則(Xをインクリメント)(設定X(ADD1のX))!!) : (定義(作りますカウンタの定義) (ラムダ(増分カウンタ)カウンタ) (define counter1(make-counter)) –