andro
andro

Reputation: 939

Named let in Scheme

I am attempting to write a loop in Scheme using named let. I would like to be able to break out of the iteration early based on various criteria, rather than always looping right at the end. Effectively, I would like to have while, break and continue. I am constrained to use guile 1.8 for strong reasons, and guile 1.8 does not implement the R6RS while construct. My question is, does recursing using named let have to be tail recursive, and why can't you restart the loop before the end? [Does this need a code example?] When I do attempt to recurse using an early exit at several point with IO operations I invariably read past EOF and get unpredictable corruption of data.

Upvotes: 0

Views: 1047

Answers (1)

Sylwester
Sylwester

Reputation: 48745

(let name ((iter iter-expr) (arg1 expr1) (arg2 expr2))
  (cond
    (continue-predicate (name (next iter) arg1 arg2)))
    (break-predicate break-expression-value)
    (else (name (next iter) next-arg1-expression next-ar2-expression))))

A continue is just calling again using most of the same arguments unchanged except the iterated parts which will change to the next thing.

A break is a base case.

So what is a while? It is a named let with a break predicate and a default case.

Scheme doesn't really have a while construct. If you read the report you'll see that it is just a syntax sugar (macro) that turns into something like a named let.

You need it to be tail recursive if you want to be able to exit it without all the previous calculations to be done. You can also use call/cc to supply an exit continuation which is basically having Scheme doing it for you under the hood. Usually call/cc is quite far out for beginners and it takes some time to master so making your procedures tail recursive is easier to understand than doing something like this:

(define (cars lists-of-pair)
  (call/cc (lambda (exit)
    (fold (lambda (e a)
            (if (pair? e)
                (cons (car e) a)
                (exit '()))) ; throw away continuations to make current result make it ()
          '()
          lists-of-pair)))

(cars '((1 2) (a b))) ; ==> (1 a)
(cars '((1 2) ()))    ; ==> ()

Upvotes: 2

Related Questions