良く判らない動作です。
Gauche でクロージャを作っていて、ちょっと良く判らない動作に遭遇しています。
先ず、以下のコードをトップレベルで評価すると意図した通りに動作してくれます。
(1) トップレベルで評価すると意図した通りに動作する。 (define (make-counter init incremental) (let ((x init) (y incremental)) (lambda () (set! x (+ x y))))) => make-counter (define c1 (make-counter 0 1)) => c1 (define c2 (make-counter 0 2)) => c2 (let loop ((n 10)) (if (< n 0) #f (begin (if (even? n) (print "(c1) => " (c1)) (print "(c2) => " (c2))) (loop (- n 1))))) => (c1) => 1 (c2) => 2 (c1) => 2 (c2) => 4 (c1) => 3 (c2) => 6 (c1) => 4 (c2) => 8 (c1) => 5 (c2) => 10 (c1) => 6 #f
しかし、これをそのまま let で包んでローカルスコープで評価すると、意図した動作をしてくれません。
(2) local scope にすると error となる。 (let () (define (make-counter init incremental) (let ((x init) (y incremental)) (lambda () (set! x (+ x y))))) (define c1 (make-counter 0 1)) (define c2 (make-counter 0 2)) (let loop ((n 10)) (if (< n 0) #f (begin (if (even? n) (print "(c1) => " (c1)) (print "(c2) => " (c2))) (loop (- n 1)))))) *** ERROR: Compile Error: [internal error] stray local variable: "(input string port)":1:(let () (define (make-counter init i ... Stack Trace: _______________________________________ 0 (report-error e) At line 167 of "/usr/local/share/gauche/site/lib/igauche.scm" 1 (call/cc (lambda (break-inner-read-eval-print-loop) (define (reade ... [unknown location]
ここで、二つ目のクロージャ生成を、単なる手続きに変えると、その様に動作します。
(3) 二つ目のクロージャ生成を止めて、単なる手続きに変えると動作する。 (let () (define (make-counter init incremental) (let ((x init) (y incremental)) (lambda () (set! x (+ x y))))) (define c1 (make-counter 0 1)) (define c2 (lambda () #f)) (let loop ((n 10)) (if (< n 0) #f (begin (if (even? n) (print "(c1) => " (c1)) (print "(c2) => " (c2))) (loop (- n 1)))))) => (c1) => 1 (c2) => #f (c1) => 2 (c2) => #f (c1) => 3 (c2) => #f (c1) => 4 (c2) => #f (c1) => 5 (c2) => #f (c1) => 6 #f
何故なんでしょう?
何か変なことをしてしまっているんでしょうけど……