I am writing a program that needs to recursively analyze a list of "commands" and "programs" (it is an interpreter of some "robotic language" invented by our professor for a robot living in a maze). Because my initial implementation was too slow, I decided to use call-with-current-continuation.
I know how call/cc works, I have read this and this as an explanation.
My call/cc is based on this part of tutorial:
Often we want to use call-with-current-continuation to call some procedure that takes arguments other than an escape procedure. For example, we might have a procedure that takes two arguments besides the escape procedure, thus:
(define (foo x y escape) ... (if (= x 0) (escape 'ERROR)) ...)) We can fix this by currying the procedure, making it a procedure of one argument.
[ An earlier chapter should have a discussion of currying! ]
Suppose we want to pass 0 and 1 as the values of x and y, as well as handing foo the escape procedure. Rather than saying
(call-with-current-continuation foo) which doesn't pass enough arguments to the call to foo, we say
(call-with-current-continuation (lambda (escape) (foo 0 1 escape))) The lambda expression creates a closure that does exactly what we want. It will call foo with arguments 0, 1, and the escape procedure created by call-with-current-continuation.
However, for some reason it doesn't work and throws this exception:
call-with-current-continuation: contract violation
expected: (any/c . -> . any)
given: #<procedure:...mazesimulator.ss:301:34>
I would like you to help me find my mistake and explain why it occurs...
Here is the part of code relevant to this question:
; 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) ))