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 - function

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

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)))

Related

Concatenate lists in Clojure Without Using concat

I am new to clojure, and am trying to understand how to concatenate lists without using the concat function.
(defn append [list1, list2]
(cond
(nil? list1) list2
:else (cons (first list1)
(append (rest list1) (list2)))))
When I run the above code, I get:
ClassCastException clojure.lang.PersistentList cannot be cast
to clojure.lang.IFn user/append
Reading from previous stackoverflow questions, it is because the cond expression is in double parentheses. I don't believe that I do.
Why am I still getting this error?
In Clojure, parentheses mean "function call". Thus the expression:
(list2)
means call a function that the list2 variable points at. This is the source of the error and the message clojure.lang.PersistentList cannot be cast to clojure.lang.IFn
Notes:
When a cond has only 2 branches, it is usually clearer to just a plain if expression.
Clojure code ignores commas, so they are normally never included in source code.
Consider carefully the difference between rest and next:
(rest []) => ()
(next []) => nil
You may wish to carefully study the Clojure CheatSheet and other documention listed here.
(defn append
[l1 l2 & [acc]]
(cond (and (empty? l1) (empty? l2)) (reverse acc)
(empty? l1) (append l1 (rest l2) (cons (first l2) acc))
:else (append (rest l1) l2 (cons (first l1) acc))))
or:
(defn append
([l1 l2]
(append l1 l2 '()))
([l1 l2 acc]
(cond (and (empty? l1) (empty? l2)) (reverse acc)
(empty? l1) (append l1 (rest l2) (cons (first l2) acc))
:else (append (rest l1) l2 (cons (first l1) acc)))))
;; or using vectors and conj
(defn vec-append
[v1 v2]
(cond (empty? v2) v1
:else (vec-append (conj v1 (first v2)) (rest v2))))
(defn append
[l1 l2]
(seq (vec-append (vec l1) (vec l2))))

Combining two functions in LISP to atomize list and then find max?

So, id like to take in a list of numbers, atomize it (to remove nested integers), then find the max value. I have two functions written that accomplish this individually, but can't figure out how to combine them in LISP so I can make one call and have them both run. Any help would be appreciated.
:Atomize function to remove nests
:(atomify ‘( a (b c) (e (f (g h) i)) j)->(a b c e f g h i j)
(defun atomify (numbers)
(cond ((null numbers) nil)
((atom (car numbers))
(cons (car numbers)
(atomify (cdr numbers))))
(t
(append (atomify (car numbers))
(atomify (cdr numbers))))))
:Max value of a list of integers function
(defun large_atom (numbers)
(if (null numbers)
0
(max (first numbers)
(large_atom (rest numbers)))))
Jamie. Your way has two steps:
1. Flatten list
2. Find max value from result of 1'st step
In this case it's true way. But you need do it with one function call. It's easy. Just use labels, apply and of course max
(defun foo (lst)
(labels ((flatten (lst acc)
(cond
((null lst)
acc)
((consp (car lst))
(flatten (cdr lst) (flatten (car lst) acc)))
(t
(flatten (cdr lst) (cons (car lst) acc))))))
(apply #'max (flatten lst nil))))
Another way, is do not flatten source list. But in this case you need find first value to compare with other values. Try it yourself.
Here is another way to solve the problem: rather than flattening the list, this walks down it recursively. This is very explicit about what the structure of the list must be: a good list is a non-null proper list each of whose elements is either an integer or a good list.
The problem with this approach is that it's not tail recursive so it will necessarily fail on very large structures (and even if it was tail recursive CL does not promise to deal with tail recursion.
(defun greatest-integer (good-list)
;; a good list is one of:
;; - a cons of a good list and either a good list or ()
;; - a cons of an integer and either a good list or ()
;; In particular it can't be () and it can't be an improper list
;;
(destructuring-bind (a . b) good-list
;; a can be an integer or a good list, b can be null or a good list
(etypecase b
(null
(etypecase a
(integer a)
(cons (greatest-integer a))))
(cons
(max (etypecase a
(integer a)
(cons (greatest-integer a)))
(greatest-integer b))))))

lisp self-developed recursive reverse function

I have writte a list reverse function in lisp and I wanted to test it but I had an error and I couldn't solve it
the function and calling is below :
(defun myreverse (list)
(cond((null list) nil))
(cons (myreverse(cdr list) (car list))))
(myreverse '(1 2 3))
any help will be appreciated...
The arguments when you defun myreverse are (list), thus when you call it (myreverse '(1 2 3)) list gets bound to (1 2 3).
Since the list is not null you suddenly do (myreverse '(2 3) 1) and list gets bound to (2 3), but what do 1 get bound to? You have no more than one argument thus the call is invalid and warrants an error.
Hint1: There is a way to make optional arguments:
(defun test (a &optional (b 0) (c 0))
(+ a b c))
(test 10) ; ==> 10
(test 10 1 2) ; ==> 13
Hint2: You need to build a list not just pass a bare element. The passed list will be the tail of the next round until the every element is added.
The bad answer (or one of the bad answers):
(defun reverse (list)
(cond ((null list) list)
(t (append (reverse (cdr list)) (cons (car list) nil)))))
A better answer:
(defun reverse (list)
(reverse-aux list nil))
(defun reverse-aux (list result)
(cond ((null list) result)
(t (reverse-aux (cdr list) (cons (car list) result)))))
It's the basic example we use in comparison to the definition of 'append' in lessons to differentiate tail recursion.

Make Scheme function for 3 parameters return function for the 3d

I'm having a hard time converting this rather simple Scheme function, into a function that returns another function taking in a list and applying the former function to all elements on that list.
This function
(define (operList op i lis)
(if (= 0 (length lis)) '()
(cons (op i (car lis)) (operList op i (cdr lis))))
)
Can be called like this
(operList + 2 '(1 1 1))
and returns '(3 3 3)
However, how can I edit this function so that I can call it in the following manner
((operList + 2) '(1 1 1))
with the same results
You have to return a new function that receives the list. I took the liberty of fixing the indentation and the base case (that's not how you should ask if a list if empty!); pay special attention to the way the recursion is called now:
(define (operList op i)
(lambda (lis)
(if (null? lis)
'()
(cons (op i (car lis))
((operList op i) (cdr lis))))))
It works as expected:
((operList + 2) '(1 1 1))
=> '(3 3 3)
You could also use map:
(define operList
(lambda (op i)
(lambda (lst)
(map
(lambda (x) (op i x))
lst))))

Creating a Function that produces a Function Scheme/DrRacket

I'm working on a function that takes in a list of structures and then using that list of structures produces a function that processes a list of symbols into a number. Each structure is made up of a symbol, that will be in the second list consumed, and a number. This function produced has to turn the list of symbols into a number by assigning each symbol a value based on the previous structures. Using abstract list functions btw.
Example: ((function (list (make-value 'value1 10) (make-value 'value2 20)))
(list 'value1 'value2 'nothing 'value1)) would produced 40.
Heres my code but it only works for specific cases.
(define (function lst)
(lambda (x) (foldr + 0 (map (lambda (x)
(cond
[(equal? x (value-name(first lst)))(value-value (first lst))]
[else (value-value (second lst))]))
(filter (lambda (x) (member? x (map value-name lst)))x)))))
Looks like a homework. Basic shape of your solution is ok. I think the reason you have a problem here is that there is no decomposition in your code so it's easy to get lost in parentheses.
Let's start with your idea of fold-ing with + over list of integers as a last step of computation.
For this subtask you have:
1) a list of (name, value) pairs
2) a list of names
and you need to get a list of values. Write a separate function which does exactly that and use it. Like this
(define (function lst)
(lambda (x) (foldr +
0
(to-values x lst)))
(define (to-values names names-to-values)
(map (lambda (name)
(to-value name names-to-values))))
(define (to-value n ns-to-vs)
...)
Here we map over the names with another little function. It will lookup the n value in ns-to-vs and return it or 0 if there is no one.
There are two approaches for solving the problem with foldr, it'd be interesting to study and understand both of them. The first one, attempted in the question, is to first produce a list with all the values and let foldr take care of adding them. It can be implemented in a simpler way like this:
(define (function lst)
(lambda (x)
(foldr +
0
(map (lambda (e)
(cond ((assoc e lst) => value-value)
(else 0)))
x))))
Alternatively: maybe using foldr is overkill, applying + is simpler:
(define (function lst)
(lambda (x)
(apply +
(map (lambda (e)
(cond ((assoc e lst) => value-value)
(else 0)))
x))))
In the second approach we take the input list "as is" and let foldr's lambda perform the addition logic. This is more efficient than the first approach using foldr, because there's no need to create an intermediate list - the one generated by map in the first version:
(define (function lst)
(lambda (x)
(foldr (lambda (e a)
(cond ((assoc e lst) => (lambda (p) (+ a (value-value p))))
(else a)))
0
x)))
In both approaches I'm using assoc for finding the element in the list; it's easy to implement as a helper function if you're not allowed to use it or if it doesn't work for the values created with make-value: assoc takes a list of name-value pairs and returns the first pair with the given name. The => syntax of cond passes the pair returned by assoc to a lambda's parameter and executes it.
And because you're using Racket, there's a bit of syntactic sugar that can be used for returning a function from another function, try this equivalent code, for simplicity's sake:
(define ((function lst) x)
(foldr +
0
(map (lambda (e)
(cond ((assoc e lst) => value-value)
(else 0)))
x)))
Or this:
(define ((function lst) x)
(foldr (lambda (e a)
(cond ((assoc e lst) => (lambda (p) (+ a (value-value p))))
(else a)))
0
x))
Anyway, the result is as expected:
((function (list (make-value 'value1 10) (make-value 'value2 20)))
(list 'value1 'value2 'nothing 'value1))
=> 40