I'm trying to write a function which takes as parameter a List and calculates the sum of even numbers minus the sum of odd numbers.
Here is my implementation but I have no clue why it is not working as expected, could you give me any hints about whats wrong?
(defun sumEvenOdd (R)
(cond
((NULL R) 0)
((and (ATOM (CAR R)) (= (mod (CAR R) 2) 0))
(+ (CAR R) (sumEvenOdd (CDR R))))
((and (ATOM (CAR R)) (not (= (mod (CAR R) 2) 0)))
(- (CAR R) (sumEvenOdd (CDR R)) ))
((LISTP (CAR R)) (sum (sumEvenOdd (CAR R)) (sumEvenOdd (CDR R))))
(T (sumEvenOdd (CDR R)))
)
)
Regarding the code algorithm, it fails because how the math is being done.
How the code is now, this the evaluation being done with the list (list 1 2 3 4 5) is (- 1 (+ 2 (- 3 (+ 4 (- 5 0))))) that equals 5.
What we were expecting was (2+4)-(1+3+5) that equals -3. What's wrong?
Basically the sum operation in math is commutative, while the subtraction operation is not. 1+5 and 5+1 is the same. 1-5 and 5-1 is not.
This reflects on the code on the last operation where 5 is being subtracted 0.
The simplest solution is to adjust the operation order, switching the arguments.
(defun sumEvenOdd (R)
(cond
((NULL R) 0)
((and (ATOM (CAR R)) (= (mod (CAR R) 2) 0))
(+ (sumEvenOdd (CDR R)) (CAR R)))
((and (ATOM (CAR R)) (not (= (mod (CAR R) 2) 0)))
(- (sumEvenOdd (CDR R)) (CAR R)))
)
)
That way the evaluation will be: (- (+ (- (+ (- 0 1) 2) 3) 4) 5) that equals -3.
PS: You can check and test the code here: http://goo.gl/1cEA5i
You are almost there. Here is an edited version of your code:
(defun sumEvenOdd (R)
(cond
((NULL R) 0)
((and (ATOM (CAR R))
(= (mod (CAR R) 2) 0))
(+ (sumEvenOdd (CDR R)) (CAR R))) ; switched places for consistency
((and (ATOM (CAR R)) (not (= (mod (CAR R) 2) 0)))
(- (sumEvenOdd (CDR R)) (CAR R))) ; operands needed to be switched
((LISTP (CAR R)) (+ (sumEvenOdd (CAR R)) ; what is sum? replaced with +
(sumEvenOdd (CDR R))))
(T (sumEvenOdd (CDR R)))))
Here is a solution using reduce:
(defun sum-even-odd (list)
(reduce (lambda (acc e)
(cond ((consp e) (+ acc (sum-even-odd e)))
((not (numberp e)) acc) ; perhaps not needed
((oddp e) (- acc e))
(t (+ acc e))))
list
:initial-value 0))
(sum-even-odd '(1 2 (3 4 (5 6) 7) 8 9 10)) ; ==> 5
If you are certain the list only has numbers or other lists with numbers the check for something that is not consp nor numberp would be redundant. This does not work for dotted lists.
There are answers with how to fix your code, but let's look at a different implementation.
You don't specify that your function needs to work on a tree so this is for a flat list of numbers.
(defun sum-even-odd (r)
(- (apply #'+ (remove-if-not #'evenp r))
(apply #'+ (remove-if-not #'oddp r))))
remove-if-not takes a list and a predicate function. It run the predicate on each element of the list and create a new list only containing the elements where the predicate didn't return nil.
apply takes a function and a list and calls the function with the arguments being the elements of the list. so (apply #'+ '(1 2 3 4)) is equivalent to (+ 1 2 3 4)
Common lisp has good functions for workings with lists (and many other data types) check em out and your code can end up much cleaner.
Also never use camel-case (or any case based naming) in common lisp and symbols are case insensitive. The symbols HeLloThErE and hellothere and helloThere are the same symbol. This is why you will see hyphens used in names.
Related
I'm trying to create a function that gets the sum of the square of the larger 2 of 3 numbers passed in. (Its exercise 1.3 in SICP)
When I run the following code I get the error ";The object #f is not applicable." If I switch the 3 and the 1 in my function call the error message will say #t instead of #f.
(define (sumOfSquareOfLargerTwoNumbers a b c) (
cond (
( (and (> (+ a b) (+ a c) ) (> (+ a b) (+ b c) ) ) (+ (square a) (square b) ) )
( (and (> (+ a c) (+ a b) ) (> (+ a c) (+ b c) ) ) (+ (square a) (square c) ) )
( (and (> (+ b c) (+ a b) ) (> (+ b c) (+ a c) ) ) (+ (square b) (square c) ) )
)
))
(sumOfSquareOfLargerTwoNumbers 1 2 3)
I was assuming the appropriate condition would return true and I'd get the square of the larger two numbers. Could someone please explain why I'm getting this error instead?
There are too many brackets in front of cond and that's causing the problem:
(cond (((and
The proper syntax for your solution should be:
(define (sumOfSquareOfLargerTwoNumbers a b c)
(cond ((and (> (+ a b) (+ a c)) (> (+ a b) (+ b c)))
(+ (square a) (square b)))
((and (> (+ a c) (+ a b)) (> (+ a c) (+ b c)))
(+ (square a) (square c)))
((and (> (+ b c) (+ a b)) (> (+ b c) (+ a c)))
(+ (square b) (square c)))))
What was happening is that the condition evaluated to a boolean, and the unexpected surrounding brackets made it look like a procedure application, so you ended up with something like this:
(#t 'something)
Which of course fails, because #t or #f are not procedures and cannot be applied. Just be careful with the brackets and use a good IDE with syntax coloring and code formatting, and you won't have this problem again.
I know what I want to do, I am having trouble getting there. I am looking for some guidance. I am more or less forcing what I want done and there has to be a better way than the way I am trying to create this function. I currently get an unbound variable error right where I call (set! nadj) and (set! count).
I am trying to make a function where the user inputs a sentence. If more than 25% of that sentence consists of adjectives the function returns false.
This is what I have so far:
(define OK
(lambda (x)
(cond
((adj? (car x))
(set! count (+ count 1)))
((not (adj? (car x))
(set! nadj (+ nadj 1))))
((not (null? (OK (cdr x)))))
((null? x)
(set! sum (+ nadj count)))
;;(set! div (/ count sum))
;;(* 100 div)
;;(< div 25))
((else #f)))))
What I am trying to do is make a counter for the words that are an adjective and a counter for the words that are not. Then I am trying to add all of the words up and divide them by the amount of words that were adjectives. I then want to multiply that by 100 and return true if it is less than 25%. I am not looking for an answer, more or less I just want some guidance.
Here is the adj? function if you need to see it.
(define adjectives '(black brown fast hairy hot quick red slow))
(define adj?
(lambda(x)
(if ( member x adjectives) #t #f)))
I am sure this isn't normal Scheme notation. I program a lot in C++ and Java and I am having a hard time transitioning into Scheme.
You're correct in stating that your solution is not idiomatic Scheme - we try really hard to avoid mutating variables, all those set! operations are frowned upon: we don't really need them. A more idiomatic solution would be to pass along the counters as parameters, as demonstrated in #uselpa's answer. His solution uses explicit recursion via a named let.
We can go one step further, though - the true spirit of functional programming is to reuse existing higher-order procedures and compose them in such a way that they solve our problems. I don't know which Scheme interpreter you're using, but in Racket the OK procedure can be expressed as simply as this:
(define (OK x) ; assuming a non-empty list
(< (/ (count adj? x) ; count the number of adjectives
(length x)) ; divide by the total number of words
0.25)) ; is it less than 25%?
If your Scheme interpreter doesn't provide a count procedure import it from SRFI-1; also it's very easy to implement your own - again, this is in the spirit of functional programming: we want to build generic procedures that are useful in their own right, and easily reused and composed in other contexts:
(define (count pred lst)
(let loop ((lst lst) (counter 0))
(cond ((null? lst) counter)
((pred (car lst)) (loop (cdr lst) (+ 1 counter)))
(else (loop (cdr lst) counter)))))
Playing Devil's advocate it's possible to fix your function using an imperative style, as long as we define the variables first (by the way, that was causing the "unbound variable" error) - for example, place a let before the looping function: think of it as a variable declaration that happens before the recursion starts. Also notice that the empty list case must appear first, to avoid accessing an element in an empty list, and don't forget to advance the recursion at each step. This is ugly, but should work:
(define (OK x) ; assuming a non-empty list
; declare the counters outside the function
(let ((adj 0) (nadj 0))
; looping function
(let loop ((x x))
(cond
; is the list empty?
((null? x)
; is the number of adjectives less than 25%?
(< (/ adj (+ adj nadj)) 0.25))
; is current element an adjective?
((adj? (car x))
; increment adj counter
(set! adj (+ adj 1))
; always advance recursion
(loop (cdr x)))
; is current element anything other than an adjective?
(else
; increment nadj counter
(set! nadj (+ nadj 1))
; always advance recursion
(loop (cdr x)))))))
I don't know if you are familiar with the named let, but this comes in handy here:
(define (OK x)
(let loop ((x x) (adj 0) (nadj 0)) ; named let
(cond
((null? x) (< (/ adj (+ adj nadj)) 0.25))
((adj? (car x)) (loop (cdr x) (+ 1 adj) nadj))
(else (loop (cdr x) adj (+ 1 nadj))))))
This is a convenient notation for the following, equivalent code:
(define (OK x)
(define (loop x adj nadj)
(cond
((null? x) (< (/ adj (+ adj nadj)) 0.25))
((adj? (car x)) (loop (cdr x) (+ 1 adj) nadj))
(else (loop (cdr x) adj (+ 1 nadj)))))
(loop x 0 0))
so basically we define an internal function, and what is a loop in a language such as C++ and Java becomes a recursive call (and to add to the confusion, the procedure that gets called recursively is sometimes called loop, as in my example). Since the call is done in tail position, this is just as efficient in Scheme as a classic loop in the languages you mentioned.
Variable assignments are replaced by modifying the parameters of the recursive call, i.e. you usually find no set! procedures in such a simple case.
EDIT an example implementation using set!:
(define OK
(let ((adj 0) (nadj 0))
(lambda (x)
(cond
((null? x) (< (/ adj (+ adj nadj)) 0.25))
(else (if (adj? (car x))
(set! adj (+ 1 adj))
(set! nadj (+ 1 nadj)))
(OK (cdr x)))))))
You can't set an unbound variable, even a global one. Variables refer to locations; setting a variable that doesn't exist anywhere is impossible:
(set! a 1)
;Unbound variable: a ; a doesn't refer to any location yet
(define a)
;Value: a
(list a)
;Unassigned variable: a ; now it does, but it hasn't been assigned a value yet
(set! a 1)
;Value: a
(list a)
;Value: (1)
(set! a 2)
;Value: 1
(list a)
;Value: (2)
There's nothing wrong with localized and encapsulated mutation. Setting a global variable is by definition not localized.
You should have created local bindings (locations) for the variables you intended to use. The basic iteration built-in form do does it for you:
(define (OK x)
(do ((adj 0) (nadj 0))
((null? x) ; loop termination condition
(< (/ adj (+ adj nadj))
0.25)) ; return value form
; loop body
(if (adj? (car x))
(set! adj (+ adj 1))
; else
(set! nadj (+ nadj 1)))
; some other statements maybe...
))
Just another option that sometimes might come handy. Of course the most idiomatic Scheme code is using named let construct. It will also force you to refactor a spaghetti code that you might otherwise write using do. Don't. :)
I started learning Racket today so please be patient :)
What I'm trying is to sum numbers (ages in this case) stored inside a struct.
So I have this:
(define-struct rec (name age)) ; defining the struct of records
(define r1 (make-rec "Joe" 23))
(define r2 (make-rec "Sue" 13))
(define r3 (make-rec "Ann" 44))
(define reclist (list r1 r2 r3)) ; defining a list of records
I found out how to sum integers, this seems a good way to do that:
(define liste (list 1 2 3 4 5))
(define (sum-list l)
(cond
[(empty? l) 0]
[(+ (first l) (sum-list (rest l)))]))
Now, I have been trying to somehow combine these functions in a way that I can grab the age inside each record and then sum them all but to no avail. I tried different loop constructs but the problem is that it never returns a value but a procedure name.
I know, I'm missing something very basic here but I'm stuck anyway.
Since your sum-list function operates only on numbers you need to project your rec list to a number list. This can be done with a map function. The expression (map rec-age reclist) will yield the number list for you.
Altering your code:
(define (sum-list lst . lkey)
(define key (if (null? lkey) values (car lkey)))
(cond
[(empty? lst) 0]
[(+ (key (first lst)) (sum-list (rest lst) key))]))
Alternative tail recursive version
(define (sum-list lst . lkey)
(define key (if (null? lkey) car (compose (car lkey) car)))
(let loop ((acc 0) (lst lst))
(if (null? lst)
acc
(loop (+ acc (key lst))
(cdr lst)))))
Alternate higher order procedure version in one blob:
(define (sum-list lst . lkey)
(define key (if (null? lkey) values (car lkey)))
(foldl (lambda (x acc)
(+ acc (key x)))
0
lst))
Using map to get the values and apply:
(define (sum-list lst . lkey)
(apply +
(if (null? lkey)
lst
(map (car lkey) lst))))
For many elements this might be more effective:
(define (sum-list lst . lkey)
(foldl +
0
(if (null? lkey)
lst
(map (car lkey) lst))))
All work like this:
(sum-list '(1 2 3 4)) ; ==> 10
(sum-list '((1)(2)(3)(4)) car) ; ==> 10
(sum-list reclist rec-age) ; ==> 80
A function that returns how many times it has been called in Scheme would look like
(define count
(let ((P 0))
(lambda ()
(set! P (+ 1 P))
P)))
(list (count) (count) (count) (count)) ==> (list 1 2 3 4)
But suppose that we have an expression that looks like this
(map ______ lst)
and we want that to evaluate to
(list 1 2 3 ... n)
where n = (length list)
The problem requires we use a lambda statement in the blank, and we cannot use any auxiliary definitions like (count) in the blank, so
(lambda (x) (count))
is not allowed. Simply replacing (count) with the previous definition like this:
(map
(lambda (x)
((let ((P 0))
(lambda ()
(set! P (+ 1 P))
P))))
L)
doesn't work either.
Any suggestions?
You're very, very close to a correct solution! in the code in the question just do this:
The outermost lambda is erroneous, delete that line and the corresponding closing parenthesis
The innermost lambda is the one that will eventually get passed to the map procedure, so it needs to receive a parameter (even though it's not actually used)
Delete the outermost parenthesis surrounding the let form
It all boils down to this: the lambda that gets passed to map receives a parameter, but also encloses the P variable. The let form defines P only once in the context of the passed lambda, and from that point on the lambda "remembers" the value of P, because for each of the elements in the list the same P is used.
You're 90% of the way there. Use the right-hand-side of your count definition in the blank, and add an (ignored) argument to the function.
(define add-stat-var
(let ( (P '()) )
(lambda (x1)
(if (equal? x1 "ResetStatVar") (set! P '()) (set! P (cons x1 P)))
P
) ;lambda
) ;let
) ;define
(define (test-add-stat-var x)
(let* ( (result '()) )
(set! result (add-stat-var 12))
(set! result (add-stat-var 14))
(set! result (add-stat-var 16))
(display (add-stat-var x)) (newline)
(set! result (add-stat-var "ResetStatVar"))
(display (cdr (add-stat-var x))) (newline)
)
)
Define a function sum, which takes two numbers, or two real functions, and returns their sum. E.g.
(sum 1 2) => 3
((sum cos exp) 0) => 2
I get that for the sum of two numbers the code would be the following:
(define sum (lambda (x y)
(+ x y)))
But what would be the code for the two real functions...? How would I do this? can anyone please help?
Also how would I do this:
Define a function sum-all which works like sum, but works on a list of numbers or a list of functions. Assume the list contains at least one element.
E.g.
(sum-all (list 1 2 3)) => 6
((sum-all (list cos sin exp)) 0) => 2
Note: this is not homework... I was going through a past midterm.
For the first part of your question, I'll have to agree with PJ.Hades that this is the simplest solution:
(define (sum x y)
(if (and (number? x) (number? y))
(+ x y)
(lambda (n)
(+ (x n) (y n)))))
For the second part, we can make good use of higher-order procedures for writing a simple solution that is a generalization of the previous one:
(define (sum-all lst)
(if (andmap number? lst)
(apply + lst)
(lambda (n)
(apply + (map (lambda (f) (f n)) lst)))))
In both procedures, I'm assuming that all the operands are of the same kind: they're either all-numbers or all-functions, as inferred from the sample code provided in the question.
Do you mean this?
(define (sum a b)
(if (and (number? a) (number? b))
(+ a b)
(lambda (x)
(+ (a x) (b x)))))
(define (sum lst)
(cond
[(empty? lst) 0]
[else (foldr + 0 lst)]))
((lambda (a b) (+ a b)) 4 5)
this how it is done using lambda.
using define we can write as follows
(define (sum a b) (+ a b))
I'm a little rusty with my Scheme, so perhaps there's a better way to do this, but you could do:
(define (sum-all lst)
(define (sum-funcs-helper funcs x)
(if (empty? funcs)
0
(+ ((car funcs) x)
(sum-funcs-helper (cdr funcs) x))))
(if (empty? lst)
0 ;; Beats me what this is supposed to return.
(if (number? (car lst))
(apply + lst)
(lambda (x) (sum-funcs-helper lst x)))))