user2980932
user2980932

Reputation: 93

Racket Contract Violation (Max Recursion Function)

Learning some Scheme/Racket, so give me some leeway.

Currently trying to find the max value when given a list without using the built-in max() function.

Current Code:

#lang racket
(provide max-num)
(define (max-num lst)
  (define (helper lst max)
    (displayln lst)
    (displayln max)
    (displayln " ")
    (when (null? max) ; first run
        (helper (cdr lst) (car lst)))
    (if (null? lst)
        max ; then end
        (if (> (car lst) max) ; else compare
            (helper (cdr lst) (car lst)) ; then update max
            (helper (cdr lst) max)))) ; else keep max
  (if (null? lst)
      #f ; then Error
      (helper lst '())) ; else run helper
  )

(max-num '())
(max-num '(1 5 2 4 3))

Output via DrRacket:

enter image description here

As far as I can tell, the displayln outputs tell me I am on the right track. However, it ends up with a contract violation real? error instead of returning the max value.

I'm guessing that the (if (null? lst)) doesn't want to return "max" at the end and instead pushes towards the else branch despite the list being empty. I've looked around and debugged for about an hour now to no avail. Any help would be greatly appreciated.

Upvotes: 1

Views: 322

Answers (1)

Sylwester
Sylwester

Reputation: 48745

You have to know that when you do:

(when test
  do-something)
do-something-else

It will always do-something-else regardless if test is true or not. SO what is happening is that the first round max is null? and it does (helper (cdr lst) (car lst))) and that returns the answer. Then it discard that answer and continue to the if with max being null? and it finally fails when it does (> (car lst) max) since a null? is not a number. The error message says it expected a real? but it got the initial value '().

So to hint you on your way you should have one expression in addition to the local definitions eg.

(if test1
    result1
    (if test2
        result2
        alternative2))

or

(cond (test1 result1)
      (test2 result2)
      (else alternative2))

And of course since you know the argument is not null? you could just call (helper (cdr lst) (car lst)) instead of passing the empty list and remove the when entirely. when and unless are for side effects and not really for good functional Scheme style.

Upvotes: 2

Related Questions