R6RS:翻訳:R6RS:B Sample definitions for derived forms

R6RS:翻訳:R6RS:B Sample definitions for derived forms

付録 B 派生形式の定義例

この付録には本報告書で説明したキーワードのいくつかをより単純な形式を使って定義した例を挙げる。

cond

cond キーワード(R6RS:翻訳:R6RS:11.4 Expressions の 11.4.5)は syntax-rules を使って、 if、 let、 begin で次のように定義できる。

(define-syntax cond
  (syntax-rules (else =>)
    ((cond (else result1 result2 ...))
     (begin result1 result2 ...))
    ((cond (test => result))
     (let ((temp test))
       (if temp (result temp))))
    ((cond (test => result) clause1 clause2 ...)
     (let ((temp test))
       (if temp
           (result temp)
           (cond clause1 clause2 ...))))
    ((cond (test)) test)
    ((cond (test) clause1 clause2 ...)
     (let ((temp test))
       (if temp
           temp
           (cond clause1 clause2 ...))))
    ((cond (test result1 result2 ...))
     (if test (begin result1 result2 ...)))
    ((cond (test result1 result2 ...)
           clause1 clause2 ...)
     (if test
         (begin result1 result2 ...)
         (cond clause1 clause2 ...)))))

case

case キーワード(R6RS:翻訳:R6RS:11.4 Expression? の 11.4.5]])は syntax-rules をつかって let、 cond、 memv (R6RS:翻訳:Standard Libraries:3 List utilities 参照)で次のように定義することができる。

(define-syntax case
  (syntax-rules (else)
    ((case expr0
       ((key ...) res1 res2 ...)
       ...
       (else else-res1 else-res2 ...))
     (let ((tmp expr0))
       (cond
         ((memv tmp ’(key ...)) res1 res2 ...)
         ...
         (else else-res1 else-res2 ...))))
    ((case expr0
       ((keya ...) res1a res2a ...)
       ((keyb ...) res1b res2b ...)
       ...)
     (let ((tmp expr0))
       (cond
         ((memv tmp ’(keya ...)) res1a res2a ...)
         ((memv tmp ’(keyb ...)) res1b res2b ...)
         ...)))))

let*

let* キーワード(R6RS:翻訳:R6RS:11.4 Expressions の 11.4.6)は syntax-rules を使って let で次のように定義することができる。

(define-syntax let*
  (syntax-rules ()
    ((let* () body1 body2 ...)
     (let () body1 body2 ...))
    ((let* ((name1 expr1) (name2 expr2) ...)
       body1 body2 ...)
     (let ((name1 expr1))
       (let* ((name2 expr2) ...)
         body1 body2 ...)))))

letrec

letrec キーワード(R6RS:翻訳:R6RS:11.4 Expressions の 11.4.6)は syntax-rules を使って、次のように補助構文を使って代入の前に値を保持する一時変数を生成して、 let と set! で近似的に定義することができる。

(define-syntax letrec
  (syntax-rules ()
    ((letrec () body1 body2 ...)
     (let () body1 body2 ...))
    ((letrec ((var init) ...) body1 body2 ...)
     (letrec-helper
       (var ...)
       ()
       ((var init) ...)
       body1 body2 ...))))

(define-syntax letrec-helper
  (syntax-rules ()
    ((letrec-helper
       ()
       (temp ...)
       ((var init) ...)
       body1 body2 ...)
     (let ((var <undefined>) ...)
       (let ((temp init) ...)
         (set! var temp)
         ...)
       (let () body1 body2 ...)))
    ((letrec-helper
       (x y ...)
       (temp ...)
       ((var init) ...)
       body1 body2 ...)
     (letrec-helper
       (y ...)
       (newtemp temp ...)
       ((var init) ...)
       body1 body2 ...))))

<undefined> という構文は、何か、ある場所に格納されると、 letrec の変換による代入が行われる前にそこから読み書きをしようとすると &assertion コンディション型の例外の起こるものを返す式を表す式を表すものである(Scheme にはそのような式は定義されていない)。

syntax-case と generate-temporaries を使ったより単純な例は R6RS:翻訳:Standard Libraries:12.7 Generating lists of temporaries に挙げられている。

letrec*

letrec* キーワードは syntax-rules を使って let と set! で次のように近似的に定義することができる。

(define-syntax letrec*
  (syntax-rules ()
    ((letrec* ((var1 init1) ...) body1 body2 ...)
     (let ((var1 <undefined>) ...)
       (set! var1 init1)
       ...
       (let () body1 body2 ...)))))

構文 <undefined> については上の letrec の定義と同様である。

let-values

次の syntax-rules を使った let-values (R6RS:翻訳:R6RS:11.4 Expressions)の定義は実変数用に一時変数を作成するのにふたつの補助構文を使っている。

(define-syntax let-values
  (syntax-rules ()
    ((let-values (binding ...) body1 body2 ...)
     (let-values-helper1
       ()
       (binding ...)
       body1 body2 ...))))

(define-syntax let-values-helper1
  ;; map over the bindings
  (syntax-rules ()
    ((let-values
       ((id temp) ...)
       ()
       body1 body2 ...)
     (let ((id temp) ...) body1 body2 ...))
    ((let-values
       assocs
       ((formals1 expr1) (formals2 expr2) ...)
       body1 body2 ...)
     (let-values-helper2
       formals1
       ()
       expr1
       assocs
       ((formals2 expr2) ...)
       body1 body2 ...))))

(define-syntax let-values-helper2
  ;; create temporaries for the formals
  (syntax-rules ()
    ((let-values-helper2
       ()
       temp-formals
       expr1
       assocs
       bindings
       body1 body2 ...)
     (call-with-values
       (lambda () expr1)
       (lambda temp-formals
         (let-values-helper1
           assocs
           bindings
           body1 body2 ...))))
    ((let-values-helper2
       (first . rest)
       (temp ...)
       expr1
       (assoc ...)
       bindings
       body1 body2 ...)
     (let-values-helper2
       rest
       (temp ... newtemp)
       expr1
       (assoc ... (first newtemp))
       bindings
       body1 body2 ...))
    ((let-values-helper2
       rest-formal
       (temp ...)
       expr1
       (assoc ...)
       bindings
       body1 body2 ...)
     (call-with-values
       (lambda () expr1)
       (lambda (temp ... . newtemp)
         (let-values-helper1
           (assoc ... (rest-formal newtemp))
           bindings
           body1 body2 ...))))))

let*-values

次のマクロは syntax-rules を使って let と let-values から let*-values を定義している。

(define-syntax let*-values
  (syntax-rules ()
    ((let*-values () body1 body2 ...)
     (let () body1 body2 ...))
    ((let*-values (binding1 binding2 ...)
       body1 body2 ...)
     (let-values (binding1)
       (let*-values (binding2 ...)
         body1 body2 ...)))))

let

let キーワードは syntax-rules を使って lambda と letrec から次のように定義することができる。

(define-syntax let
  (syntax-rules ()
    ((let ((name val) ...) body1 body2 ...)
     ((lambda (name ...) body1 body2 ...)
      val ...))
    ((let tag ((name val) ...) body1 body2 ...)
     ((letrec ((tag (lambda (name ...)
                      body1 body2 ...)))
        tag)
      val ...))))
More ...