functionrecursionsyntax-errorracketself-reference

Function body for a function that consumes a compound data list of universities and produces the name of school with the lowest tuition. BSL RACKET


Hello everyone Im having trouble coding the body for a function that consumes a compound data list of universities and produces the name of the university with the lowest tuition.

The language is BSL Racket.

Compound Data Definition:

(define-struct uni (name tuition))

interp. a university name as a string and its tuition as a 
natural

(define UNI-1 (make-uni "UBC" 28500))
; example of compound data definition

The List Data Definition For The Universities:

ListOfUni is one of:
  - empty
  - (cons uni ListOfUni)
 interp. a list of unis

(cons (make-uni "SFU" 27797) (cons (make-uni "UVIC" 26000) 
    empty))

Function Introduced:

 (lowest? lou) 

This is a function that consumes list of unis and produces the 
name of school with the lowest tuition 

The Check-Expects:

(check-expect (lowest? empty) "none")
(check-expect (lowest? (cons (make-uni "UBC" 28500) empty)) 
"UBC")
(check-expect (lowest? (cons (make-uni "SFU" 27797) (cons (make- 
uni "UVIC" 26000) empty))) "UVIC")

Attempt at function body:

 (define (lowest? lou)
  (cond [(empty? lou) "none"]
        [(empty? (rest lou)) (uni-name (first lou))]
        [else (if  (<(uni-tuition (first lou)) (uni-tuition (lowest? (rest lou))))
                (uni-name (first lou))
                (lowest? (rest lou)))]))

Error Message Given:

1 of the 3 tests failed.

Check failures:
 check-expect encountered the following error instead of the 
expected value, "UVIC". 
   :: uni-tuition: expects an uni, given "UVIC"

I don't understand how to get around this error and still have the code be recursive.

Also Please excuse any formatting errors, this is my first post on StackOverFlow


Solution

  • When you're iterating over the list of universities, you have to return uni struct from each step, because you call uni-tuition on the result: (uni-tuition (lowest? (rest lou)))

    But when lou has only one element, your function returns (uni-name (first lou)) and that is a string. That is the meaning of the error message: :: uni-tuition: expects an uni, given "UVIC"

    There are probably more ways to solve this exercise, but given BSL limitations (no let, or and and work only for #true and #false values), I had to come up with helper function and "none" university created with (make-uni "none" 0):

    (define-struct uni (name tuition))
    
    (define (lowest-helper lou)
      (cond [(empty? lou) (make-uni "none" 0)]
            [(empty? (rest lou)) (first lou)]
            [(< (uni-tuition (first lou))
                (uni-tuition (lowest-helper (rest lou))))
             (first lou)]
            [else
             (lowest-helper (rest lou))]))
    
    (define (lowest? lou)
      (uni-name (lowest-helper lou)))
    
    (check-expect (lowest? empty) "none")
    (check-expect (lowest? (cons (make-uni "UBC" 28500) empty)) 
    "UBC")
    (check-expect (lowest? (cons (make-uni "SFU" 27797)
                                 (cons (make-uni "UVIC" 26000) empty))) "UVIC")
    

    Or you can return either "none" or uni struct and add a new function to differentiate between them:

    (define (get-name result)
      (if (string? result)
          result
          (uni-name result)))
    
    (define (lowest? lou)
      (get-name (lowest-helper lou)))