0

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.

apaderno
  • 28,547
  • 16
  • 75
  • 90
andro
  • 901
  • 9
  • 20
  • 1
    It would be useful to show what you've tried so far. You mention `while`, `break` and `continue`: it sounds as if you're trying to import imperative ideas (C-style) into a non-imperative language, and thus trying to write _extremely_ unidiomatic scheme. – Norman Gray May 22 '17 at 08:00
  • 1
    (and regarding your specific questions: no, recursing doesn't have to be a tail call; yes, you can restart the ‘loop’ at any point; and yes, a code example would help) – Norman Gray May 22 '17 at 08:28
  • Except that Guile 2 sees fit to incorporate the while construct as a new feature. My context is in fact Guile. Guile is indeed for integrating with C/C++ code and this sort of imperative thing does come up from time time. We are not talking 'pure' Scheme here (if you see what I mean). – andro May 22 '17 at 08:37
  • No, but if your system expects you to control the C/C++ code using Guile, then it (presumably) expects you to program that Guile layer in a Guile-idiomatic way. If you're looking for `break` and `continue`, you'll look for a long time, since there are no immediate analogues of those in schemes. – Norman Gray May 22 '17 at 09:56

1 Answers1

2
(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) ()))    ; ==> ()
Sylwester
  • 47,942
  • 4
  • 47
  • 79
  • Of course you mean 'So what is a while? It is a named let with a continue predicate and a default case.' – andro May 22 '17 at 13:12
  • @andro a `while` is doing recursion if a predicate is true so you can think of it as recursion unless a negated base case hits. Thus `break` with `(not while-predicate)` as predicate. `continue` usually has recursion, like the default case, but with less calculations. – Sylwester May 22 '17 at 13:28