[racket-dev] Simple loop checking in beginner?

From: John Clements (clements at brinckerhoff.org)
Date: Tue Nov 9 21:13:39 EST 2010

Here's a simple macro that prevents same-argument recursive calls (including non-tail ones).  It's illustrated by a student function that made a teeny mistake which would result in looping forever, but (using this macro) instead signals an error.  To the best of my limited knowledge, beginner is purely functional aside from the use of the test functions, right? So any recursive call with eq? args is guaranteed to loop forever, right?

Hmm... well, I suppose there's (random)... 

It seems to me that a macro like this one (or even complete memoization) could potentially reduce student frustration, and would not prevent students from writing the programs that they wanted to.

No?

John Clements



#lang racket

(require rackunit)

(define-syntax (define/noloop stx)
  (syntax-case stx ()
    [(_ (funname arg ...) body ...)
     #`(define funname
         (let ()
           (define fresh-key (gensym 'funname))
           (define (funname arg ...)
             (let* ([most-recent-args (continuation-mark-set-first #f fresh-key)]
                    [these-args (list arg ...)])
               (when (and most-recent-args
                          (= (length these-args)
                             (length most-recent-args))
                          (andmap eq? these-args most-recent-args))
                 (error 'funname "recursive call with identical arguments ~s is guaranteed to run forever." these-args))
               (with-continuation-mark fresh-key these-args
                 body
                 ...)))
           funname))]))

;; NOW I'M A STUDENT:

;; only-long-strings : (listof string) -> (listof string)
;; return a list containing the strings longer than 2 chars
(define/noloop (only-long-strings l)
  (cond [(empty? l) empty]
        [else (cond [(< 2 (string-length (first l))) 
                     (cons (first l) 
                           (only-long-strings (rest l)))]
                    [else (only-long-strings l)])]))


(check-equal? (only-long-strings (cons "abc" (cons "de" (cons "fgh" empty))))
              (cons "abc" (cons "fgh" empty)))
-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/pkcs7-signature
Size: 4669 bytes
Desc: not available
URL: <http://lists.racket-lang.org/dev/archive/attachments/20101109/4d3d69db/attachment.p7s>

Posted on the dev mailing list.