Gauche の手続き : 3

呼称: ローカル変数と可変長引数
目的: ローカル変数とスコープ、可変長引数の取得方法を学ぶ

ローカル変数には let 式を使用します。

;; <初期値式> が評価され、その値が <変数> に束縛される
;; これが一般形?
(let ((<変数1> <初期値式1>)
      (<変数2> <初期値式2>)
      ・・・
      (<変数N> <初期値式N>))
  <式> ...)

;; <初期値式> の評価順序を保証する
(let* ((<変数1> <初期値式1>)
       (<変数2> <初期値式2>)
       ・・・
       (<変数N> <初期値式N>))
  <式> ...)

;; <変数1> 〜 <変数N> が見えているスコープで
;; <初期値式1> 〜 <初期値式N> を評価する
(letrec ((<変数1> <初期値式1>)
         (<変数2> <初期値式2>)
         ・・・
         (<変数N> <初期値式N>))
  <式> ...)

letrec は <初期値式> が lambda 式である場合や「ローカルな再帰手続き」を書くのに有効です。内部的には、ローカル手続きは letrec 式へ展開され、let 式は lambda 式へと展開されるようです。

;; lambda 式と let 式の表記、内容は等価
gosh> ((lambda (a b) (+ a b)) 1 2)
gosh> (let ((a 1) (b 2)) (+ a b))
3

;; ローカル手続きと letrec 式の表記、内容は等価
(define (revl lis)
  (define (revl-rec init lis)
    (if (null? lis)
      init
      (revl-rec (cons (car lis) init) (cdr lis))))
  (revl-rec '() lis))

gosh> (revl '(1 2 3))
(3 2 1)

(define (revr lis)
  (letrec ((revr-rec (lambda (init lis)
                       (if (null? lis)
                         init
                         (revr-rec (cons (car lis) init) (cdr lis))))))
    (revr-rec '() lis)))

gosh> (revr '(1 2 3))
(3 2 1)

次に可変長引数を取る手続きの定義です。

;; 「2個以上の引数」
(define (func a b . c) ...)
または
(define (func (lambda (a b . c) ...))

;; 「0個以上の引数」
(define (func . a) ...)
または
(define func (lambda a ...))

練習問題。

;; 引数をリストで返す手続き list を定義する
(define my-list (lambda a cons '() a))

gosh> (my-list 1 2 3)
(1 2 3)
gosh> (my-list 1)
(1)
gosh> (my-list)
()