Combined weight of items in list - recursion

I'm working in Dr. Racket, and it's my first time using a functional language so I am quite confused.
I just need to add the weights of each different "animal" in a list.
All the different animals have a "weight" attribute, but racket won't let me access the "weight" item of any given list element because it claims it's "not defined"
What I have so far:
(define (zoo-weight animals)
(cond [(empty? animals) 0]
[else (+ (first weight)(zoo-weight (rest animals)))])) ;This is where I get the error for weight, saying it is undefined.
If someone could just let me know how to reference weight regardless of list item (snake-weight, cow-weight, etc) this whole functional thing is just sort of confusing.
Thanks!

You almost got it! try something like this:
(define (zoo-weight animals)
(cond [(empty? animals) 0]
[else (+ (weight (first animals))
(zoo-weight (rest animals)))]))
The problem is that you can't say (first weight). What is weight? it's probably a function that applies to animals, or a variable. So, you wrote: "take the first element of weight". Clearly that doesn't make sense, we want to take the first animal from the list, and then find out that animal's weight, before advancing to the next animal in the list.
As shown above use the following expression in your procedure, it should work assuming that the function that gives us an animal's weight is called weight (if not, use the appropriate function - animal-wight, weight-animal, I don't know how you called it):
(weight (first animals))
UPDATE
Now that you mention that each animal has a different weight function, I have a couple of comments. This is a symptom of bad design, the same function should work on all kinds of animals, to avoid those long conditionals everywhere (and it'll be a hassle if we add a new kind of animal!). I don't know how the animals are currently implemented, so I can't make further suggestions. But if it's not possible to fix the current representation, at least encapsulate the conditional in a single place, like this:
(define (weight animal)
; find the correct weight function
((cond ((snake? animal) snake-weight)
((dillo? animal) dillo-weight)
((ant? animal) ant-weight)
(else (error "Unknown animal:" animal)))
; apply the function to the animal
animal))
Now my implementation of zoo-weight will work without any modification, and there's no need to duplicate the conditional wherever the weight is needed. And if writing more than one function is a problem (and I can't imagine why your teacher would put that restriction, functional programming encourages building lots of reusable functions!), we can always in-line the code:
(define (zoo-weight animals)
(cond [(empty? animals) 0]
[else (+ (let ([animal (first animals)])
((cond ((snake? animal) snake-weight)
((dillo? animal) dillo-weight)
((ant? animal) ant-weight)
(else (error "Unknown animal:" animal)))
animal))
(zoo-weight (rest animals)))]))
Also, borrowing from #Jack's solution, we can use a lambda (an anonymous function) together with the higher-order map procedure. This still counts as a single function:
(define (zoo-weight animals)
(apply +
(map
(lambda (animal)
((cond ((snake? animal) snake-weight)
((dillo? animal) dillo-weight)
((ant? animal) ant-weight)
(else (error "Unknown animal:" animal)))
animal))
animals)))

Assuming you've got a list of animals and a function weight that takes one animal and gives you its weight, you mgiht be better off using apply and map here instead of doing the recursion yourself:
(define (zoo-weight animals)
(apply + (map weight animals)))
map takes a function and a list and calls the function once for each thing in the list, e.g. (map sqrt '(9 16 25)) evaluates to the list '(3 4 5). The apply function takes a function and a list and calls the function with the list items as arguments, e.g. (apply + '(1 2 3)) is the same as (+ 1 2 3). By combining the two, you get the functionality you want. It can be difficult to learn to think in terms of these patterns, but once you do the benefits are enormous. But you should get a solid understanding of the recursive pattern in Oscar Lopez's answer first, that is absolutely fundamental to understanding functional programming patterns.
Update
That bit about not having a general weight function and only being allowed to create one is quite the restriction. Normally in functional languages, lots of general functions and helper functions are good to have. You can use the anonymous function approach outlined in Oscar's answer, but I would add that it might be good to bind this function to a name in the body of the zoo-weight function using a let:
(define (zoo-weight animals)
(let ([weight (lambda (animal)
((cond [(snake? animal) snake-weight]
[(dillo? animal) dillo-weight]
[(ant? animal) ant-weight]
[else (error "Unknown animal:" animal)])
animal))])
(apply + (map weight animals)))
You can also achieve the same thing with an inner define:
(define (zoo-weight animals)
(define (weight animal)
((cond [(snake? animal) snake-weight]
[(dillo? animal) dillo-weight]
[(ant? animal) ant-weight]
[else (error "Unknown animal:" animal)])
animal))
(apply + (map weight animals)))
This is basically the same thing as defining a separate helper function, but the weight function is hidden inside the zoo-weight function - no code anywhere outside the zoo-weight function can use the helper.
As Joshua notes, there are other higher-order functions you can use such as variants of foldl. foldl take a function, an initial value, and a list and reduces the list to one value using the function in steps. (foldl + 0 '(1 2 3)) is the same as (foldl + 1 '(2 3)) which is the same as (foldl + 3 '(3)) which is 6. In Racket, using foldl instead of (apply + (map weight animals)) would look like either of these:
(foldl + 0 (map weight animals))
(foldl (lambda (animal acc) (+ acc (weight animal))) 0 animals)
Racket also offers the for/fold macro, which can make the logic clearer at times:
(for/fold ([sum 0]) ([animal animals])
(+ sum (weight animal)))
This folding function based on Common Lisp's reduce works as well:
(define (reduce f xs #:key [key-func #f])
(let ([xs (if key-func (map key-func xs) xs)])
(foldl f (first xs) (rest xs))))
(reduce + animals #:key weight)

Thank you all for your responses, I gave up-votes for your time. All of your answers are good, except that I'm only allowed one function, so I couldn't make a "weight" function that gets the weight of any animal. I ended up having to do it with a large "cond" statement below. I know this is less good code, but it gets the job done without having to build any other functions (which is my only option):
(define (zoo-weight animals)
(cond [(empty? animals) 0]
[(snake? (first animals)) (+(snake-weight (first animals))(zoo-weight (rest animals)))]
[(dillo? (first animals)) (+(dillo-weight (first animals))(zoo-weight (rest animals)))]
[(ant? (first animals)) (+(ant-weight (first animals))(zoo-weight (rest animals)))]
))
Thanks again, all of your answers helped me to get here!

Related

Recursion with more than one function

some of you may find this question a little odd, but i really want to know if this program is recursive or not, and that is all I want to know.
(defun howmany(sez)
(if (null sez)
0
(+ 1 (howmany (cdr sez)))))
(defun sum(sez)
(if (null sez)
0
(+ (car sez) (sum(cdr sez)))))
(defun avg(sez)
(if (null sez)
0
(/ (sum sez) (howmany sez))))
(print (avg '(100 200 300)))
Thank for all your answers!
First, take a look at your code and format it a little bit more, in order to be easily read by a lisper
(defun howmany (sez)
(if (null sez)
0
(+ 1 (howmany (cdr sez)))))
(defun sum (sez)
(if (null sez)
0
(+ (car sez) (sum (cdr sez)))))
(defun avg (sez)
(if (null sez)
0
(/ (sum sez) (howmany sez))))
(print (avg '(100 200 300)))
Then analize this script, it contains three functions an a last s-expression which evaluate the functions.
For this three functions, avg, sum and howmany,
There is a story titled Martin and the Dragon, you can find in chapter 8 from here Common Lisp: A Gentle Introduction to Symbolic Computation and you should read, which sumarizes in:
The dragon, beneath its feigned distaste for Martin's questions,
actually enjoyed teaching him about recursion. One day it decided to
formally explain what recursion means. The dragon told Martin to
approach every recursive problem as if it were a journey. If he
followed three rules for solving problems recursively, he would always
complete the journey successfully.
The dragon explained the rules this way:
Know when to stop.
Decide how to take one step.
Break the journey down into that step plus a smaller journey.
Let's see the functions howmany and sum
Know when to stop
it stops when sez is null, i.e. when the list is nil
Decide how to take one step
the if have two ways or 0 for both or
(+ 1 (howmany (cdr sez)))
(+ (car sez) (sum (cdr sez)))
Break the joourney down into that step plus a smaller journey
in the last expressions, the list is smaller take out the first and then continue, with the smaller list
So, this two functions are recursive, the other avg, is not recursive, only take cares of the empty list, in order to prevent dividing by zero or zero/zero indetermination.
Hope this helps

Build lazy-seq by multiplying previous term by constant

I'm starting out with Clojure and, despite having an understanding of recursion, am having trouble thinking of the "right" way to build a lazy-seq for the following function:
I want to build a list of all the frequencies starting from middle C. My first element would be 120 (the frequency of middle C). To get the second element, I'd multiply the first element, 120, by 1.059463 to get 127.13556. To the get the third I'd multiply the second element, 127.13556, by 1.059463, etc etc...
What's the best way to do this in Clojure?
You can use the iterate function for that.
(iterate #(* % 1.059463) 120)
If you are planning to expand this into something more complicated, then you would create a function that recursive calls itself inside a call to lazy-seq. (This is what iterate does internally.)
(defn increasing-frequencies
([] (increasing-frequencies 120))
([freq]
(cons freq (lazy-seq (increasing-frequencies (* freq 1.059463))))))
(nth (increasing-frequencies) 2) ;; => 134.69542180428002
If you start to use this in a tight loop, you may also want to generate a chunked lazy seq. This will pre-calculate the next few elements, instead of one by one.
(defn chunked-increasing-frequencies
([] (chunked-increasing-frequencies 120))
([freq]
(lazy-seq
(let [b (chunk-buffer 32)]
(loop [i freq c 0]
(if (< c 32)
(do
(chunk-append b i)
(recur (* i 1.059463) (inc c)))
(chunk-cons (chunk b) (chunked-increasing-frequencies i))))))))
Note: I would advise against doing this until you have measured a performance problem related to calculating individual elements.
(defn get-frequencies []
(iterate #(* 1.059463 %) 120))
See iterate
Or, if you want to use lazy-seq explicitly, you can do this:
(defn get-frequencies-hard []
(cons
120
(lazy-seq
(map #(* 1.059463 %) (get-frequencies-hard)))))
Which will cons 120 to a lazy seq of every value applied to the map function.

Count amount of odd numbers in a sentence

I am fairly new to lisp and this is one of the practice problems.
First of all, this problem is from simply scheme. I am not sure how to answer this.
The purpose of this question is to write the function, count-odd that takes a sentence as its input and count how many odd digits are contained in it as shown below:
(count-odd'(234 556 4 10 97))
6
or
(count-odd '(24680 42 88))
0
If possible, how would you be able to do it, using higher order functions, or recursion or both - whatever gets the job done.
I'll give you a few pointers, not a full solution:
First of all, I see 2 distinct ways of doing this, recursion or higher order functions + recursion. For this case, I think straight recursion is easier to grok.
So we'll want a function which takes in a list and does stuff, so
(define count-odd
(lambda (ls) SOMETHING))
So this is recursive, so we'd want to split the list
(define count-odd
(lambda (ls)
(let ((head (car ls)) (rest (cdr ls)))
SOMETHING)))
Now this has a problem, it's an error for an empty list (eg (count-odd '())), but I'll let you figure out how to fix that. Hint, check out scheme's case expression, it makes it easy to check and deal with an empty list
Now something is our recursion so for something something like:
(+ (if (is-odd head) 1 0) (Figure out how many odds are in rest))
That should give you something to start on. If you have any specific questions later, feel free to post more questions.
Please take first into consideration the other answer guide so that you try to do it by yourself. The following is a different way of solving it. Here is a tested full solution:
(define (count-odd num_list)
(if (null? num_list)
0
(+ (num_odds (car num_list)) (count-odd (cdr num_list)))))
(define (num_odds number)
(if (zero? number)
0
(+ (if (odd? number) 1 0) (num_odds (quotient number 10)))))
Both procedures are recursive.
count-odd keeps getting the first element of a list and passing it to num_odds until there is no element left in the list (that is the base case, a null list).
num_odds gets the amount of odd digits of a number. To do so, always asks if the number is odd in which case it will add 1, otherwise 0. Then the number is divided by 10 to remove the least significant digit (which determines if the number is odd or even) and is passed as argument to a new call. The process repeats until the number is zero (base case).
Try to solve the problem by hand using only recursion before jumping to a higher-order solution; for that, I'd suggest to take a look at the other answers. After you have done that, aim for a practical solution using the tools at your disposal - I would divide the problem in two parts.
First, how to split a positive integer in a list of its digits; this is a recursive procedure over the input number. There are several ways to do this - by first converting the number to a string, or by using arithmetic operations to extract the digits, to name a few. I'll use the later, with a tail-recursive implementation:
(define (split-digits n)
(let loop ((n n)
(acc '()))
(if (< n 10)
(cons n acc)
(loop (quotient n 10)
(cons (remainder n 10) acc)))))
With this, we can solve the problem in terms of higher-order functions, the structure of the solution mirrors the mental process used to solve the problem by hand:
First, we iterate over all the numbers in the input list (using map)
Split each number in the digits that compose it (using split-digits)
Count how many of those digits are odd, this gives a partial solution for just one number (using count)
Add all the partial solutions in the list returned by map (using apply)
This is how it looks:
(define (count-odd lst)
(apply +
(map (lambda (x)
(count odd? (split-digits x)))
lst)))
Don't be confused if some of the other solutions look strange. Simply Scheme uses non-standard definitions for first and butfirst. Here is a solution, that I hope follows Simply Scheme friendly.
Here is one strategy to solve the problem:
turn the number into a list of digits
transform into a list of zero and ones (zero=even, one=odd)
add the numbers in the list
Example: 123 -> '(1 2 3) -> '(1 0 1) -> 2
(define (digit? x)
(<= 0 x 9))
(define (number->digits x)
(if (digit? x)
(list x)
(cons (remainder x 10)
(number->digits (quotient x 10)))))
(define (digit->zero/one d)
(if (even? d) 0 1))
(define (digits->zero/ones ds)
(map digit->zero/one ds))
(define (add-numbers xs)
(if (null? xs)
0
(+ (first xs)
(add-numbers (butfirst xs)))))
(define (count-odds x)
(add-numbers
(digits->zero/ones
(number->digits x))))
The above is untested, so you might need to fix a few typos.
I think this is a good way, too.
(define (count-odd sequence)
(length (filter odd? sequence)))
(define (odd? num)
(= (remainder num 2) 1))
(count-odd '(234 556 4 10 97))
Hope this will help~
The (length sequence) will return the sequence's length,
(filter proc sequence) will return a sequence that contains all the elements satisfy the proc.
And you can define a function called (odd? num)

Finding sub-lists within a list

I'm a real scheme newbie and i'm trying to work out how to return all the sub-lists given with a list argument (i.e. (1 2 (3 4 5) (6 7 8) 9) should return the two lists (3 4 5) and (6 7 8)).
I know I should be using a recursive function with the rest of the list but I'm having trouble producing the results I want. Here is what I've written: -
(define (find-sublists list)
(cond
((null? list) #t))
(not
(list? (first list)))
(print (first list))
(find-sublists (rest list)))
I'm trying to search through the list and output anything which is a list and then search again, otherwise just recursively search the rest of the list. However I'm not sure how to jump straight to the last line when the condition is met.
Does anybody have any advice for me?
First, I'm assuming that this is a homework assignment; please correct me if I'm wrong.
Next: It looks to me like you have one vital misunderstanding of the problem: it asks you to return the two lists, not to print them.
Next, I'm going to steer you to the How To Design Programs design recipe. Your first step is to write down the data definition that you're working with--I'm not quite sure what it is here, but it might be something like this:
;; a list-of-maybe-lists is either
;; - empty, or
;; - (cons maybe-list list-of-maybe-lists)
;; a maybe-list is either
;; - a list, or
;; - something else
Your next step is to write down a contract and a purpose statement for your program, and then some test cases.
Boilerplate: please forgive me for giving you lots of little steps rather than the answer; the point of all these steps is to enable you to fish for yourself, rather than just waiting for other people to fish for you.
If you just want to filter out all the lists in a given list, use filter:
(filter list? '(1 2 (3 4 5) (6 7 8) 9))
or you implement it yourself:
(define (my-filter func lst)
(cond ((null? lst) '())
((func (car lst))
(cons (car lst) (my-filter func (cdr lst))))
(else
(my-filter func (cdr lst)))))

how many elements on list with scheme

i need to write a function which calculates how many elements on list with scheme language.
for example
(howMany 'a) returns 0
(howMany '(a b)) returns 1
(howMany '(a (b c))) returns 2
how can i do that? i did not want a working code, just only an idea for do that. so maybe you should consider to remove working codes. :) thank you
The fold answers will work. However, if this is homework, you may be trying to do this using only simple built-in functions. There are two possible answers.
Here's the naive way:
(define (howMany list)
(if (null? list)
0
(+ 1 (howMany (cdr list)))
)
)
(Your implementation of Scheme may have a function empty? instead of null?.)
However, this algorithm will take an amount of space linearly proportional to the number of elements in the list, because it will store (+ 1 ...) for each element of the list before doing any of the additions. Intuitively, you shouldn't need this. Here's a better algorithm that avoids that issue:
(define (howMany list)
(define (iter numSoFar restOfList)
(if (null? restOfList)
numSoFar
(iter (+ numSoFar 1) (cdr restOfList))
)
)
(iter 0 list)
)
(Bonus points: use Scheme's (let iter ...) syntax to write this more succinctly. I used this style because it's more clear if you only know a few Scheme primitives.)
This will most likely get down-voted for this phrase, but, I don't know scheme. I am, however, familiar with functional programming.
If there is no built-in for this, start by 'folding' the list with start value of 0 and add 1 on every additional fold.
It is simply counting the number of elements in the list.
(define howMany
(lambda (list)
(cond
[(not (list? list)) 0]
[(null? list) 0]
[else (+ 1 (howMany (cdr list)))])))

Resources