「コマンド」と「プログラム」のリストを再帰的に分析する必要があるプログラムを作成しています(これは、迷路に住むロボットのために教授によって発明された「ロボット言語」のインタープリターです)。私の最初の実装は遅すぎたため、call-with-current-continuation を使用することにしました。
call/cc がどのように機能するかは知っています。これとこれを説明として読みました。
私の call/cc はチュートリアルのこの部分に基づいています:
多くの場合、call-with-current-continuation を使用して、エスケープ プロシージャ以外の引数を取るプロシージャを呼び出します。たとえば、エスケープ手続き以外に 2 つの引数を取る手続きがあるとします。
(define (foo xy escape) ... (if (= x 0) (escape 'ERROR)) ...)) これは、手続きをカリー化して 1 引数の手続きにすることで修正できます。
[ 前の章でカリー化について議論すべきです! ]
x と y の値として 0 と 1 を渡し、foo にエスケープ プロシージャを渡したいとします。と言うより、
(call-with-current-continuation foo) foo への呼び出しに十分な引数を渡さない、
(call-with-current-continuation (lambda (escape) (foo 0 1 escape))) ラムダ式は、まさに私たちが望むことを行うクロージャを作成します。これは、引数 0、1、および call-with-current-continuation によって作成されたエスケープ プロシージャで foo を呼び出します。
ただし、何らかの理由で機能せず、次の例外がスローされます。
call-with-current-continuation: contract violation
expected: (any/c . -> . any)
given: #<procedure:...mazesimulator.ss:301:34>
私の間違いを見つけて、なぜそれが起こるのかを説明してほしい...
この質問に関連するコードの部分は次のとおりです。
; main program
(define (simulate state expression-list program limit)
; read the input and set global variables
(set! current-orientation (list-ref state 2))
(set! current-coordinates (list-ref state 1))
(set! current-maze (list-ref state 0))
; call the inner function
(call-with-current-continuation (lambda (exit)
(command state expression-list program limit exit)))
; this is the output
(list list-of-executed-commands (list current-maze current-coordinates current-orientation))
)
;; main recursive function
;; analyses expression-list parameter
;; evaluates its elements
;; and calls itself on the cdr of the espression-list
(define (command state expression-list program limit exit)
(if (and (not (null? expression-list))(equal? stop-command #f))
; recursion end condition, the whole procedure will be done only
; if the list is still not empty
(if (atom? expression-list) ;if the list consists of only one command
(if (equal? stop-command #f) ;positive branch - if there were no erros before
(atomic-command state expression-list program limit exit) ;call atomic-command on this element
;when flag is set to #t
(exit))
; here comes a problem with "inner ifs"
(if (atom? (car expression-list)) ;negative branch - if the first element is "if"
(if (equal? (car expression-list) 'if) ;if the list consisits only of if-clause, no other commands ((if ...))
(if ((name->function (list-ref expression-list 1))) ;evaluate the boolean - wall? north? and choose corresponding branch
(command state (list-ref expression-list 2) program limit exit)
(command state (list-ref expression-list 3) program limit exit))
(evaluate-first-and-call-command-on-rest expression-list program limit exit))
(if (equal? (car(car expression-list)) 'if) ;if the if-clause is not the only element in list - "inner if" ((if ...) turn-left put-mark)
(begin ;not only evaluate if-clause,
(if ((name->function (list-ref (car expression-list) 1)))
(command state (list-ref (car expression-list) 2) program limit exit)
(command state (list-ref (car expression-list) 3) program limit exit))
(command state (cdr expression-list) program limit exit)) ;but also call command on cdr!
(evaluate-first-and-call-command-on-rest expression-list program limit exit))))
;when limit is exceeded or when the flag is set to #t
(exit) ))