2016年10月11日火曜日

開発環境

Scheme でクロージャー、環境について考えてる時、処理系によってエラーになったりならなかったり、結果が違うことを見つけた。

その他参考書籍

試した処理系/翻訳系(インタプリタ/コンパイラ/JIT)は、Gauche、Guile、MIT/GNU Scheme、CHICKEN Scheme(とkscheme(ksi))。

結果が違ったコード

コード(Emacs)

sample1.scm

01: (begin
02:   (define (p o) (display o) (newline))
03:   
04:   ((lambda (add)
05:      (set! + (lambda (x y) (add x y)))
06:      )
07:    +)
08:   
09:   (define add #f)
10:   (p (+ 2 3))
11:   (p (+ 2 3 4))
12:   )
13: 

sample2.scm

01: (begin
02:   (define (p o) (display o) (newline))
03: 
04:   ((lambda ()
05:      (define add +)
06:      (set! + (lambda (x y) (add x y)))))
07:   
08:   (define add #f)
09:   (p (+ 2 3))
10:   (p (+ 2 3 4))
11:   )
12: 

入出力結果(Terminal(kscheme), REPL(Read, Eval, Print, Loop))

001: $ gosh sample1.scm
002: WARNING: altering binding of inlinable procedure: scheme#+
003: 5
004: 9
005: $ gosh sample2.scm
006: WARNING: altering binding of inlinable procedure: scheme#+
007: 5
008: 9
009: $ guile sample1.scm
010: ;;; note: auto-compilation is enabled, set GUILE_AUTO_COMPILE=0
011: ;;;       or pass the --no-auto-compile argument to disable.
012: ;;; compiling /Users/kamimura/Desktop/sample1.scm
013: ;;; compiled /Users/kamimura/.cache/guile/ccache/2.0-LE-8-2.0/Users/kamimura/Desktop/sample1.scm.go
014: 5
015: 9
016: $ guile sample2.scm
017: ;;; note: auto-compilation is enabled, set GUILE_AUTO_COMPILE=0
018: ;;;       or pass the --no-auto-compile argument to disable.
019: ;;; compiling /Users/kamimura/Desktop/sample2.scm
020: ;;; compiled /Users/kamimura/.cache/guile/ccache/2.0-LE-8-2.0/Users/kamimura/Desktop/sample2.scm.go
021: 5
022: 9
023: $ rm ~/.cache/guile/ccache/2.0-LE-8-2.0/Users/kamimura/Desktop/sample*
024: remove /Users/kamimura/.cache/guile/ccache/2.0-LE-8-2.0/Users/kamimura/Desktop/sample1.scm.go? y
025: remove /Users/kamimura/.cache/guile/ccache/2.0-LE-8-2.0/Users/kamimura/Desktop/sample2.scm.go? y
026: $ guile --no-auto-compile sample1.scm
027: 5
028: Backtrace:
029: In ice-9/boot-9.scm:
030:  160: 10 [catch #t #<catch-closure 1068d5460> ...]
031: In unknown file:
032:    ?: 9 [apply-smob/1 #<catch-closure 1068d5460>]
033: In ice-9/boot-9.scm:
034:   66: 8 [call-with-prompt prompt0 ...]
035: In ice-9/eval.scm:
036:  432: 7 [eval # #]
037: In ice-9/boot-9.scm:
038: 2404: 6 [save-module-excursion #<procedure 1067de940 at ice-9/boot-9.scm:4051:3 ()>]
039: 4058: 5 [#<procedure 1067de940 at ice-9/boot-9.scm:4051:3 ()>]
040: 1727: 4 [%start-stack load-stack ...]
041: 1732: 3 [#<procedure 1068fe6c0 ()>]
042: In unknown file:
043:    ?: 2 [primitive-load "/Users/kamimura/Desktop/sample1.scm"]
044: In ice-9/eval.scm:
045:  387: 1 [eval # ()]
046:  416: 0 [#<procedure 106908cf0 at ice-9/eval.scm:416:20 (a b)> 2 3 4]
047: 
048: ice-9/eval.scm:416:20: In procedure #<procedure 106908cf0 at ice-9/eval.scm:416:20 (a b)>:
049: ice-9/eval.scm:416:20: Wrong number of arguments to #<procedure 106908cf0 at ice-9/eval.scm:416:20 (a b)>
050: $ guile --no-auto-compile sample2.scm
051: 5
052: Backtrace:
053: In ice-9/boot-9.scm:
054:  160: 10 [catch #t #<catch-closure 1085e61a0> ...]
055: In unknown file:
056:    ?: 9 [apply-smob/1 #<catch-closure 1085e61a0>]
057: In ice-9/boot-9.scm:
058:   66: 8 [call-with-prompt prompt0 ...]
059: In ice-9/eval.scm:
060:  432: 7 [eval # #]
061: In ice-9/boot-9.scm:
062: 2404: 6 [save-module-excursion #<procedure 1083b7940 at ice-9/boot-9.scm:4051:3 ()>]
063: 4058: 5 [#<procedure 1083b7940 at ice-9/boot-9.scm:4051:3 ()>]
064: 1727: 4 [%start-stack load-stack ...]
065: 1732: 3 [#<procedure 1086156c0 ()>]
066: In unknown file:
067:    ?: 2 [primitive-load "/Users/kamimura/Desktop/sample2.scm"]
068: In ice-9/eval.scm:
069:  387: 1 [eval # ()]
070:  416: 0 [#<procedure 10861fc30 at ice-9/eval.scm:416:20 (a b)> 2 3 4]
071: 
072: ice-9/eval.scm:416:20: In procedure #<procedure 10861fc30 at ice-9/eval.scm:416:20 (a b)>:
073: ice-9/eval.scm:416:20: Wrong number of arguments to #<procedure 10861fc30 at ice-9/eval.scm:416:20 (a b)>
074: $ mit-scheme < sample1.scm
075: MIT/GNU Scheme running under OS X
076: Type `^C' (control-C) followed by `H' to obtain information about interrupts.
077: 
078: Copyright (C) 2014 Massachusetts Institute of Technology
079: This is free software; see the source for copying conditions. There is NO
080: warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
081: 
082: Image saved on Thursday March 10, 2016 at 8:26:27 PM
083:   Release 9.2 || Microcode 15.3 || Runtime 15.7 || SF 4.41 || LIAR/C 4.118
084:   Edwin 3.116
085: 
086: 1 ]=> (begin
087:   (define (p o) (display o) (newline))
088:   
089:   ((lambda (add)
090:      (set! + (lambda (x y) (add x y)))
091:      )
092:    +)
093:   
094:   (define add #f)
095:   (p (+ 2 3))
096:   (p (+ 2 3 4))
097:   )5
098: ;The procedure #[compound-procedure 2] has been called with 3 arguments; it requires exactly 2 arguments.
099: ;To continue, call RESTART with an option number:
100: ; (RESTART 1) => Return to read-eval-print level 1.
101: 
102: 2 error> 
103: End of input stream reached.
104: Moriturus te saluto.
105: $ mit-scheme < sample2.scm
106: MIT/GNU Scheme running under OS X
107: Type `^C' (control-C) followed by `H' to obtain information about interrupts.
108: 
109: Copyright (C) 2014 Massachusetts Institute of Technology
110: This is free software; see the source for copying conditions. There is NO
111: warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
112: 
113: Image saved on Thursday March 10, 2016 at 8:26:27 PM
114:   Release 9.2 || Microcode 15.3 || Runtime 15.7 || SF 4.41 || LIAR/C 4.118
115:   Edwin 3.116
116: 
117: 1 ]=> (begin
118:   (define (p o) (display o) (newline))
119: 
120:   ((lambda ()
121:      (define add +)
122:      (set! + (lambda (x y) (add x y)))))
123:   
124:   (define add #f)
125:   (p (+ 2 3))
126:   (p (+ 2 3 4))
127:   )5
128: ;The procedure #[compound-procedure 2] has been called with 3 arguments; it requires exactly 2 arguments.
129: ;To continue, call RESTART with an option number:
130: ; (RESTART 1) => Return to read-eval-print level 1.
131: 
132: 2 error> 
133: End of input stream reached.
134: Moriturus te saluto.
135: $ csi sample1.scm
136: 
137: CHICKEN
138: (c) 2008-2013, The Chicken Team
139: (c) 2000-2007, Felix L. Winkelmann
140: Version 4.8.0.2 (stability/4.8.0) (rev b7e1215)
141: macosx-unix-clang-x86-64 [ 64bit manyargs dload ptables ]
142: compiled 2013-02-19 on aeryn.xorinia.dim (Darwin)
143: 
144: ; loading sample1.scm ...
145: 5
146: 
147: Error: bad argument count - received 3 but expected 2: #<procedure (+ x y)>
148: 
149:         Call history:
150: 
151:         <syntax>          (##core#begin (define add #f) (p (+ 2 3)) (p (+ 2 3 4)))
152:         <syntax>          (define add #f)
153:         <syntax>          (##core#set! add #f)
154:         <syntax>          (p (+ 2 3))
155:         <syntax>          (+ 2 3)
156:         <syntax>          (##core#begin (p (+ 2 3 4)))
157:         <syntax>          (p (+ 2 3 4))
158:         <syntax>          (+ 2 3 4)
159:         <eval>    ((lambda (add) (set! + (lambda (x y) (add x y)))) +)
160:         <eval>    (p (+ 2 3))
161:         <eval>    (+ 2 3)
162:         <eval>    [+] (add x y)
163:         <eval>    [p] (display o)
164:         <eval>    [p] (newline)
165:         <eval>    (p (+ 2 3 4))
166:         <eval>    (+ 2 3 4)     <--
167: $ csi sample2.scm
168: 
169: CHICKEN
170: (c) 2008-2013, The Chicken Team
171: (c) 2000-2007, Felix L. Winkelmann
172: Version 4.8.0.2 (stability/4.8.0) (rev b7e1215)
173: macosx-unix-clang-x86-64 [ 64bit manyargs dload ptables ]
174: compiled 2013-02-19 on aeryn.xorinia.dim (Darwin)
175: 
176: ; loading sample2.scm ...
177: 5
178: 
179: Error: bad argument count - received 3 but expected 2: #<procedure (+ x y)>
180: 
181:         Call history:
182: 
183:         <syntax>          (##core#begin (define add #f) (p (+ 2 3)) (p (+ 2 3 4)))
184:         <syntax>          (define add #f)
185:         <syntax>          (##core#set! add #f)
186:         <syntax>          (p (+ 2 3))
187:         <syntax>          (+ 2 3)
188:         <syntax>          (##core#begin (p (+ 2 3 4)))
189:         <syntax>          (p (+ 2 3 4))
190:         <syntax>          (+ 2 3 4)
191:         <eval>    ((lambda () (define add +) (set! + (lambda (x y) (add x y)))))
192:         <eval>    (p (+ 2 3))
193:         <eval>    (+ 2 3)
194:         <eval>    [+] (add x y)
195:         <eval>    [p] (display o)
196:         <eval>    [p] (newline)
197:         <eval>    (p (+ 2 3 4))
198:         <eval>    (+ 2 3 4)     <--
199: $ ksi < sample1.scm
200: ksi> 5
201: Error: #<compound-procedure (x y) ((add x y))> wrong number of arguments -- (4)
202: ksi> $ ksi < sample2.scm
203: ksi> 5
204: Error: #<compound-procedure (x y) ((add x y))> wrong number of arguments -- (4)
205: ksi> $ 
206: 

(+ 2 3 4) について、Gauche(gosh 1行目、5行目)は警告有り(2行目、6行目)、Guileはコンパイル有り(9行目、16行目)だと警告無し、コンパイルしない(--no-auto-compile、26行目、50行目)とエラー、MIT/GNU Scheme(mit-scheme、74行目、105行目)、CHICKEN Scheme(csi、135行目、167行目)、kscheme(ksi、199行目、202行目) はエラー。

実行前に想像してたのは、エラー。(引数の個数が異なる)

こんな感じ。

;; 大域環境(グローバル)
+: 基本手続き(+)

;; 4行目で環境1ができる
add: 基本手続き(+)

;; 5行目から見える順。
環境1[add: 基本手続き(+)]
大域環境[+: 基本手続き(+)]

;; (set! + (lambda (x y) (add x y)))で
環境1[add: 基本手続き(+)]
大域環境[+: (lambda (x y) (add x y))
           {環境1[add: 基本手続き(+)]、大域環境[+: 基本手続き(+)]}]

;; (環境1、大域環境)出て、8行目から
大域環境[+: (lambda (x y) (add x y))
            {環境1[add: 基本手続き(+)]、大域環境[+: 基本手続き(+)]}]
;; 10行目の式の評価
(+ 2 3 4)
((lambda (x y) (add x y z)) 2 3 4)
;; 引数の個数が合わない

どれも仕様通りなのか、それとも、Gauche と Guile はコンパイルによる高速化、最適化で、再定義される可能性が低い、基本手続き(+)の部分を何か変換するのか。(Gauche は警告出してくれるけど、Guile はコンパイル時に何も警告出さないのが少し気になったり。)

0 コメント:

コメントを投稿