[racket] Forcing termination of a for loop

From: Robert Wilkinson (bob at fourtheye.org)
Date: Sat Nov 9 13:32:28 EST 2013

Hello

I am learning to program in racket - and have questions regarding forcing
the exit from a for loop. I wrote the following program to determine the
largest prime factor of a number. (The correct answer being 11 in the case
of input 165)
-------------------------------------------------------------------------
#lang racket
(define number 165)
(define maxp 0)

(define (divides? a b)
  (= (remainder a b) 0))

(define (set-vars i) 
  (set! maxp i)
  (set! number (/ number i))
)

(define (loop)
  (for ([i (in-range 3 number 2)] #:break (= number 1))
    (if (divides? number i)
      (set-vars i)  
      0
    )
  )
)

(loop)
(printf "~a\n" maxp)
-------------------------------------------------------------------------
I decided to try to improve this and then wrote
-------------------------------------------------------------------------
#lang racket
; this computes the largest prime factor of the odd number maxnum
(define maxnum 165)

(define (divides? a b)
    (= (remainder a b) 0))

(define (divides-yes i stepn)
  (set! maxnum (/ maxnum i))
  (ploop i maxnum stepn)
)

(define (ploop minn maxn stepn) 
  (for ([i (in-range minn (+ 1 maxn) stepn)] #:break (= maxnum 1))
    (if (= maxnum i)
       (printf "~a\n" i)
       0
    )
    (if (divides? maxnum i)
       (divides-yes i stepn)
       (ploop (+ minn stepn) maxn stepn)
    )
  )
)

(ploop 3 maxnum 2)
-------------------------------------------------------------------------
My third attempt avoided me having to use set!, but I find that it does 
not terminate as I expect.
-------------------------------------------------------------------------
#lang racket
(define maxnum 165)

(define (divides? a b)
    (= (remainder a b) 0))

(define (case-stop start stop step)
  (printf "CASE-STOP ~s, ~s, ~s\n" start stop step)
  (ploop 0 start stop 0)
)

(define (case-divide start stop step)
  (printf "CASE-DIVIDE ~s, ~s, ~s\n" start stop step)  
  (ploop 1 start stop step)
)

(define (case-else start stop step)
  (printf "CASE-ELSE ~s, ~s, ~s\n" start stop step)  
  (ploop 1 start stop step)
)

(define (gosub start stop step)
  (printf "GO ~s, ~s, ~s\n" start stop step)
  (for ([i (in-range start (+ 1 stop) step)] #:break (= step 0))
        (cond [(= stop i)        (case-stop start stop 0)] 
              [(divides? stop i) (case-divide i (/ stop i) step)]
              [ else             (case-else (+ start step) stop step)]
        )
  )
)

(define (stopsub start stop step)
  (printf "STOP ~s, ~s, ~s\n" start stop step)
)

(define (ploop go start stop step)
  (if (= go 1)
      (gosub start stop step)
      (stopsub start stop 0)
  )
)

(ploop 1 3 maxnum 2)
--------------------------------------------------------------------
I expect the function, ploop, to terminate when invoked with the 
first parameter set to 0, but it doesn't. I did try stopping the loop 
with a #:break on one parameter which I set explicitly to stop the 
loop but that did not do what I wanted either. (I am aware that the
code will not handle even numbers correctly but I want to get it to
work with odd numbers first). I want the loop inside the function
gosub to terminate but I am not able to force it to do so?

(I noticed that the code ran under Racket v5.3.4. but under 
Racket v5.2.1. none of the code ran - it showed 
for: bad sequence binding clause at: #:break?)

I hope that my intention is clear, and any advice would be
gratefully received, as to how I can correct the third program.

Bob

Posted on the users mailing list.