NightMare
NightMare

Reputation: 38

Unexpected error in simple recursion(Scheme Language)

I'm learning Scheme using racket. I made the following program but it gives a contract violation error.

expected: (exact-nonnegative-integer? . -> . any/c) given: '()

The program finds a list of all numbers in an interval which are divisible by 3 or 5.

#lang racket

;;Global Definitions
(define upper-bound 10)
(define lower-bound 0)


;;set-bounds: Int, Int -> ()
(define (set-bounds m n)
(set! upper-bound (max m n))
(set! lower-bound (min m n)))

;;get-numbers: () -> (Int)
(define (get-numbers)
    (build-list upper-bound '()))

;;make-list: Int, (Int) -> (Int)
(define (build-list x y)
    (cond
        [(= x lower-bound) y]
        [(= (modulo x 5) 0) (build-list (sub1 x) (cons x y))]
        [(= (modulo x 3) 0) (build-list (sub1 x) (cons x y))]
        [else (build-list (sub1 x) y)]))

EDIT: I made the changes suggested by Oscar Lopez.

Upvotes: 0

Views: 88

Answers (2)

rnso
rnso

Reputation: 24535

An alternative method can be with the use of for/list to create the list:

(define (build-list ub lst)
  (for/list ((i (range lb ub))
             #:when (or (= 0 (modulo i 3))
                        (= 0 (modulo i 5))))
    i))

Usage:

(define lb 0)
(build-list 10 '())

Output:

'(0 3 5 6 9)

Edit:

Actually lst is not needed here:

(define (build-list ub)
  (for/list ((i (range lb ub))
             #:when (or (= 0 (modulo i 3))
                        (= 0 (modulo i 5))))
    i))

So one can call:

(build-list 10)

Following is a modification of the recursion method (uses 'named let'):

(define (build-list2 ub)
  (let loop ((x ub) (lst '()))
    (cond
        [(= x lb) lst]
        [(= (modulo x 5) 0) (loop (sub1 x) (cons x lst))]
        [(= (modulo x 3) 0) (loop (sub1 x) (cons x lst))]
        [else (loop (sub1 x) lst)])))

Also, if you always have to call your function with an empty list '(), you can put this as default in your argument list:

(build-list x (y '()))

Then you can call with simplified command:

(build-list 10)

Upvotes: 1

Óscar López
Óscar López

Reputation: 235984

You should test first the condition where the recursion stops - namely, when x equals the lower-bound:

(define (build-list x y)
  (cond
    [(= x lower-bound) y]
    [(= (modulo x 5) 0) (build-list (sub1 x) (cons x y))]
    [(= (modulo x 3) 0) (build-list (sub1 x) (cons x y))]
    [else (build-list (sub1 x) y)]))

Upvotes: 1

Related Questions