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)))
Description: S/MIME cryptographic signature
_________________________________________________ For list-related administrative tasks: http://lists.racket-lang.org/listinfo/dev