create an infinite loop to build a REPL in scheme - scheme

It strikes me beautiful, how i can create a REPL in Common Lisp using:
(loop (print (eval (read))))
However, since I'm a complete noob in Lisp (and dialects), I miserably failed to achieve the same in Scheme, due to the lacking loop function.
I tried to implement it as
(define (loop x) x (loop x))
But that doesn't seem to do anything (even when called as (loop (print 'foo))
So the question is: how to implement an infinite loop in Scheme?

(define (loop x)
x
(loop x))
This is an infinite loop when you call it. But it does not erad, evaluate or print. It takes an argument x, evaluates it then throws it away before callng itself with the same argument and it repeats.
For a REPL you want something like this:
(define (repl)
(display (eval (read))) ; for side effect of printing only
(repl))
Usually a REPL has a way to exit:
(define (repl)
(let ((in (read)))
(when (not (eq? in 'exit))
(print (eval in))
(repl))))

Related

Just eval first symbol (CHICKEN Scheme)

How can I evaluate an s-expression only by the first term?
(define (fn x y) (print x) (print y))
(eval '(fn a b))
I am trying to evaluate something like this on a bigger expression but the interpreter is complaining that a and b variables don't exist (unbound variable a).
Is there something I can do to leave symbols as they are?
I have been trying to find information about this but I can't find it anywhere.
How about the following?
(let ((expr '(fn a b)))
(cons (eval (car expr)) (cdr expr)))
But please note that if you have to rely on eval, you're almost certainly doing things wrong.

Maximum recursion error [duplicate]

I'm reading The Little Schemer. And thanks to my broken English, I was confused by this paragraph:
(cond ... ) also has the property of not considering all of its
arguments. Because of this property, however, neither (and ... ) nor
(or ... ) can be defined as functions in terms of (cond ... ), though
both (and ... ) and (or ... ) can be expressed as abbreviations of
(cond ... )-expressions:
(and a b) = (cond (a b) (else #f)
and
(or a b) = (cond (a #t) (else (b))
If I understand it correctly, it says (and ...) and (or ...) can be replaced by a (cond ...) expression, but cannot be defined as a function that contains (cond ...). Why is it so? Does it have anything to do with the variant arguments? Thanks.
p.s. I did some searching but only found that (cond ...) ignores the expressions when one of its conditions evaluate to #f.
Imagine you wrote if as a function/procedure rather than a user defined macro/syntax:
;; makes if in terms of cond
(define (my-if predicate consequent alternative)
(cond (predicate consequent)
(else alternative)))
;; example that works
(define (atom? x)
(my-if (not (pair? x))
#t
#f))
;; example that won't work
;; peano arithemtic
(define (add a b)
(my-if (zero? a)
b
(add (- a 1) (+ b 1))))
The problem with my-if is that as a procedure every argument gets evaluated before the procedure body gets executed. thus in atom? the parts (not (pair? x)), #t and #f were evaluated before the body of my-if gets executed.
For the last example means (add (- a 1) (+ b 1)) gets evaluated regardless of what a is, even when a is zero, so the procedure will never end.
You can make your own if with syntax:
(define-syntax my-if
(syntax-rules ()
((my-if predicate consequent alternative)
(cond (predicate consequent)
(else alternative)))))
Now, how you read this is the first part is a template where the predicate consequent and alternative represent unevaluated expressions. It's replaced with the other just reusing the expressions so that:
(my-if (check-something) (display 10) (display 20))
would be replaced with this:
(cond ((check-something) (display 10))
(else (display 20)))
With the procedure version of my-if both 10 and 20 would have been printed. This is how and and or is implemented as well.
You cannot define cond or and or or or if as functions because functions evaluate all their arguments. (You could define some of them as macros).
Read also the famous SICP and Lisp In Small Pieces (original in French).

"cond","and" and "or" in Scheme

I'm reading The Little Schemer. And thanks to my broken English, I was confused by this paragraph:
(cond ... ) also has the property of not considering all of its
arguments. Because of this property, however, neither (and ... ) nor
(or ... ) can be defined as functions in terms of (cond ... ), though
both (and ... ) and (or ... ) can be expressed as abbreviations of
(cond ... )-expressions:
(and a b) = (cond (a b) (else #f)
and
(or a b) = (cond (a #t) (else (b))
If I understand it correctly, it says (and ...) and (or ...) can be replaced by a (cond ...) expression, but cannot be defined as a function that contains (cond ...). Why is it so? Does it have anything to do with the variant arguments? Thanks.
p.s. I did some searching but only found that (cond ...) ignores the expressions when one of its conditions evaluate to #f.
Imagine you wrote if as a function/procedure rather than a user defined macro/syntax:
;; makes if in terms of cond
(define (my-if predicate consequent alternative)
(cond (predicate consequent)
(else alternative)))
;; example that works
(define (atom? x)
(my-if (not (pair? x))
#t
#f))
;; example that won't work
;; peano arithemtic
(define (add a b)
(my-if (zero? a)
b
(add (- a 1) (+ b 1))))
The problem with my-if is that as a procedure every argument gets evaluated before the procedure body gets executed. thus in atom? the parts (not (pair? x)), #t and #f were evaluated before the body of my-if gets executed.
For the last example means (add (- a 1) (+ b 1)) gets evaluated regardless of what a is, even when a is zero, so the procedure will never end.
You can make your own if with syntax:
(define-syntax my-if
(syntax-rules ()
((my-if predicate consequent alternative)
(cond (predicate consequent)
(else alternative)))))
Now, how you read this is the first part is a template where the predicate consequent and alternative represent unevaluated expressions. It's replaced with the other just reusing the expressions so that:
(my-if (check-something) (display 10) (display 20))
would be replaced with this:
(cond ((check-something) (display 10))
(else (display 20)))
With the procedure version of my-if both 10 and 20 would have been printed. This is how and and or is implemented as well.
You cannot define cond or and or or or if as functions because functions evaluate all their arguments. (You could define some of them as macros).
Read also the famous SICP and Lisp In Small Pieces (original in French).

Scheme call/cc issue - implementing exit.

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) ))
New follow-up: So at this point I am puzzled by the poster's question. GoZoner has pointed out that the continuation passed by call/cc may require an actual parameter when invoked, but this is not generally true in Racket (which, based on the poster's error message, is the language implementation that I assume is under discussion).
Furthermore, the code snippet that the original poster put in the question is incomplete, so one cannot directly execute the code in an attempt to replicate the problem. (My informal analysis hasn't revealed an obvious bug in the use of call-with-current-continuation that was presented by the original poster.) It would be useful if the original poster could derive a minimal (or at least smaller) test case that exposes the same issue.
It could be that one of the specific languages or language levels within Racket uses a more restrictive form of call/cc, but I have not found evidence of such a language level. I will pose the question to the original poster.
Edit: Chris-Jester Young has pointed out that my commentary may not apply properly here (see comments on this answer). I need to more carefully investigate the Racket's handling of continuations in imperative code; the notes below may be leading the asker down an incorrect path. (I plan to delete this answer if I can confirm that my notes below are bogus.)
Follow-up edit: It appears that Racket's handling of call/cc does indeed pass along a continuation that will accept zero values when it is invoked from a context that discards the value. For example:
(define global 7)
(define (goner exit)
(set! global 11)
(exit)
(set! global 13)
(* 2 3))
(define (hi)
(define x global)
(call-with-current-continuation goner)
(* 5 x global))
(* 5 7 11)
(hi)
The above prints 385 (twice); once for (* 5 7 11), and once for (hi).
(Original commentary follows)
The fact that you are invoking (exit) with zero arguments leads me to think that you do not completely understand how call/cc works (as in its observable behavior), despite your claim to the contrary.
I recommend you play with some small examples, completely independently of your professor's robot maze infrastructure, before you try to incorporate call/cc into your solution.
For example, I can readily reproduce your error message this way:
(define (goner)
(* 2 3))
(define (hi)
(let ((x (call-with-current-continuation goner)))
(* 5 x)))
(hi)
From the above, I get:
call-with-current-continuation: contract violation
expected: (any/c . -> . any)
given: #<procedure:goner>
which is quite similar to your error message, no? (Though to be honest, that might just be a coincidence).
Compare the output from the run above with the outputs from runs of:
(define (goner exit)
(* 2 3))
(define (hi)
(let ((x (call-with-current-continuation goner)))
(* 5 x)))
(hi)
and:
(define (goner exit)
(* 2 (exit)))
(define (hi)
(let ((x (call-with-current-continuation goner)))
(* 5 x)))
(hi)
and:
(define (goner exit)
(* 2 (exit 3)))
(define (hi)
(let ((x (call-with-current-continuation goner)))
(* 5 x)))
(hi)
and:
(define (goner exit)
(* (exit 2) 3))
(define (hi)
(let ((x (call-with-current-continuation goner)))
(* 5 x)))
(hi)
Give some careful thought to what each is illustrating, and think about how it might matter in the case of your program.
The call/cc 'escape procedure' expects a single argument. You are calling it as (exit) without the required argument. Different Scheme implementations will handle this differently. Here is one that complains:
1 ]=> (define (doit exit)
(display "DOIT2\n")
(exit)) ;; no argument, expect error
;Value: doit
1 ]=> (define (try)
(call-with-current-continuation
(lambda (exit) (display "TRY\n") (doit exit)))
'done)
;Value: try
1 ]=> (try)
TRY
DOIT2
;The procedure #[continuation 13] has been called with 0 arguments; it requires exactly 1 argument.
The reason that the 'escape procedure' expects a value is that call/cc, like all Scheme functions, needs to produce a value. The argument that is provided is the return value of call/cc when the escape procedure is invoked.

How Do For Loops Work In Scheme?

I'm having some difficulty understanding how for loops work in scheme. In particular this code runs but I don't know why
(define (bubblesort alist)
;; this is straightforward
(define (swap-pass alist)
(if (eq? (length alist) 1)
alist
(let ((fst (car alist)) (scnd (cadr alist)) (rest (cddr alist)))
(if (> fst scnd)
(cons scnd (swap-pass (cons fst rest)))
(cons fst (swap-pass (cons scnd rest)))))))
; this is mysterious--what does the 'for' in the next line do?
(let for ((times (length alist))
(val alist))
(if (> times 1)
(for (- times 1) (swap-pass val))
(swap-pass val))))
I can't figure out what the (let for (( is supposed to do here, and the for expression in the second to last line is also a bit off putting--I've had the interpreter complain that for only takes a single argument, but here it appears to take two.
Any thoughts on what's going on here?
That's not a for loop, that's a named let. What it does is create a function called for, then call that; the "looping" behavior is caused by recursion in the function. Calling the function loop is more idiomatic, btw. E.g.
(let loop ((times 10))
(if (= times 0)
(display "stopped")
(begin (display "still looping...")
(loop (- times 1)))))
gets expanded to something like
(letrec ((loop (lambda (times)
(if (= times 0)
(display "stopped")
(begin (display "still looping...")
(loop (- times 1)))))))
(loop 10))
This isn't actually using a for language feature but just using a variation of let that allows you to easily write recursive functions. See this documentation on let (it's the second form on there).
What's going on is that this let form binds the name it's passed (in this case for) to a procedure with the given argument list (times and val) and calls it with the initial values. Uses of the bound name in the body are recursive calls.
Bottom line: the for isn't significant here. It's just a name. You could rename it to foo and it would still work. Racket does have actual for loops that you can read about here.

Resources