Lisp Recursion Issue With Stack - recursion

I have just hit another bump in the road along my journey with Scheme. It's probably safe to say my table has had enough of me banging my head into it... I have written a function to find the min and max number within a list for class homework. The logic is sound (i think so...) and everything works fine, however, only the value of the first function call is returned from the (define (iterator aList minNum maxNum)). What I am noticing with the debugger is that after every recursion / function call I see (using DrRacket) that function call being pushed to the stack. Once the recursion happens for the last time and the code jumps down to the return of (list minNum maxNum) it doesn't return what it should, as I can see the values are correct, instead I see the function calls coming off the stack one by one until it gets to the very first one. Thus the initial values which would be the first two values form the list are returned instead. I know the stack is FIFO, however, I am not even trying to push anything to the stack. In theory I just want to call the function again and keep passing values back up... Any guidance on this would be much appreciated.
(define (findMinMax aList)
(define (iterator aList minNum maxNum)
(when(not(null? aList))
(cond
((> minNum (car aList))
(set! minNum (car aList)))
((< maxNum (car aList))
(set! maxNum (car aList))))
(iterator (cdr aList) minNum maxNum))
(list minNum maxNum))
(cond ; setting the first two atoms in a list appropriately to the min and max variables.
((< (car aList) (car(cdr aList)))
(iterator (cdr (cdr aList)) (car aList) (car(cdr aList))))
((> (car aList) (car(cdr aList)))
(iterator (cdr (cdr aList)) (car(cdr aList)) (car aList)))
(else
(iterator (cdr (cdr aList)) (car aList) (car(cdr aList))))))

Your sophistication with Scheme is already much better than most on SO! There is a very useful Scheme syntactic keyword 'named-let' that makes it easy to define internal, recursive function definitions. Here is an example to take you to the next level:
(define (findMinMax list)
(assert (not (null? list)))
(let finding ((list (cdr list))
(lMin (car list))
(lMax (car list)))
(if (null? list)
(values lMin lMax)
(finding (cdr list)
(min lMin (car list))
(max lMax (car list))))))
Note also that I've used the values syntactic form to return two values. And, I used builtin functions min and max. Also, the use of finding is tail-recursive meaning that the Scheme compiler converts this recursive call into an iterative call and thus no stack frame is required.

You need to rewrite the code not to use either set! or when since it's holding you back on learning Scheme. You have to think differently when writing in a Lisp dialect than an Algol dialect so try just making the change in the recursion rather than using set! and use 3 way if and just one expression in the body of a procedure.
(define (my-length lst)
(define (length-aux lst n)
(if (null? lst)
n ; base case, return the length
(length-aux (cdr lst) (+ n 1)))) ; instead of set! we put the new value as argument
(length-aux lst 0)) ; one expression that calls the auxiliary procedure to do the calculations
Your internal procedure can be made just as simple:
(define (iterator aList minNum maxNum)
(if (null? <???>)
(list minNum maxNum)
(iterator <???>
(min <???> <???>)
(max <???> <???>))))
Or maybe with if instead of min/max
(define (iterator aList minNum maxNum)
(if (null? <???>)
(list minNum maxNum)
(let ((n (car aList))) ; use n to compare with minNum/maxNum
(iterator <???>
(if <???> <???> <???>)
(if <???> <???> <???>))))

You have some misleading indentation. Indentation step of 1 is really not advisable. 2 is OK but 4 is better while you're learning Scheme.
You actually just need to make some minimal changes, syntax-wise. Instead of
(define (findMinMax aList)
(define (iterator aList minNum maxNum)
(when (not (null? aList))
(cond
((> minNum (car aList)) ; change the local
(set! minNum (car aList))) ; variable's value
((< maxNum (car aList))
(set! maxNum (car aList))))
(iterator (cdr aList) minNum maxNum)) ; pass new values on, but
; ignore recursive result, and
(list minNum maxNum)) ; return the current values instead!
you need:
(define (findMinMax aList)
(define (iterator aList minNum maxNum)
(if (not (null? aList))
(begin
(cond
((> minNum (car aList))
(set! minNum (car aList)))
((< maxNum (car aList))
(set! maxNum (car aList))))
(iterator (cdr aList) minNum maxNum)) ; return recursive result!
(list minNum maxNum))) ; ELSE - base case
the initial call is just:
(iterator (cdr aList) (car aList) (car aList)))

Yes stay away from set! or you won't learn the ropes of the functional aspect of scheme. You can use it if something is otherwise very messy but it's rare that that's the case.
A lot of answers here are expressed in terms of recursion, but often simpler to understand are higher order functions
Both the built-in min and max are defined in some implementations in terms of fold.
(define (min first . L) (fold (lambda (x y) (if (< x y) x y)) first L))
(define (max first . L) (fold (lambda (x y) (if (> x y) x y)) first L))
(define (MinMax first . L)
(define (internal y x)
(let ((min (car x))
(max (cdr x)))
(cons (if (< min y) min y)
(if (> max y) max y))))
(fold internal (cons first first) L))
Notice how much cleaner the code is when you can fit what your doing to a higher order function. Two lines to define the ADT, Two lines to tell fold how to carry along the local state, and one line for the actual procedure.
;;Sample Call
> (minmax 0 9 3 4 7 6 -2)
;Value 4: (-2 . 9)

Related

Recursive function to calculate the powerset of a set [duplicate]

I'm using the beginning language with list abbreviations for DrRacket and want to make a powerset recursively but cannot figure out how to do it. I currently have this much
(define
(powerset aL)
(cond
[(empty? aL) (list)]
any help would be good.
What's in a powerset? A set's subsets!
An empty set is any set's subset,
so powerset of empty set's not empty.
Its (only) element it is an empty set:
(define
(powerset aL)
(cond
[(empty? aL) (list empty)]
[else
As for non-empty sets, there is a choice,
for each set's element, whether to be
or not to be included in subset
which is a member of a powerset.
We thus include both choices when combining
first element with smaller powerset,
that, which we get recursively applying
the same procedure to the rest of input:
(combine (first aL)
(powerset (rest aL)))]))
(define
(combine a r) ; `r` for Recursive Result
(cond
[(empty? r) empty] ; nothing to combine `a` with
[else
(cons (cons a (first r)) ; Both add `a` and
(cons (first r) ; don't add, to first subset in `r`
(combine ; and do the same
a ; with
(rest r))))])) ; the rest of `r`
"There are no answers, only choices". Rather,
the choices made, are what the answer's made of.
In Racket,
#lang racket
(define (power-set xs)
(cond
[(empty? xs) (list empty)] ; the empty set has only empty as subset
[(cons? xs) (define x (first xs)) ; a constructed list has a first element
(define ys (rest xs)) ; and a list of the remaining elements
;; There are two types of subsets of xs, thouse that
;; contain x and those without x.
(define with-out-x ; the power sets without x
(power-set ys))
(define with-x ; to get the power sets with x we
(cons-all x with-out-x)) ; we add x to the power sets without x
(append with-out-x with-x)])) ; Now both kind of subsets are returned.
(define (cons-all x xss)
; xss is a list of lists
; cons x onto all the lists in xss
(cond
[(empty? xss) empty]
[(cons? xss) (cons (cons x (first xss)) ; cons x to the first sublist
(cons-all x (rest xss)))])) ; and to the rest of the sublists
To test:
(power-set '(a b c))
Here's yet another implementation, after a couple of tests it appears to be faster than Chris' answer for larger lists. It was tested using standard Racket:
(define (powerset aL)
(if (empty? aL)
'(())
(let ((rst (powerset (rest aL))))
(append (map (lambda (x) (cons (first aL) x))
rst)
rst))))
Here's my implementation of power set (though I only tested it using standard Racket language, not Beginning Student):
(define (powerset lst)
(if (null? lst)
'(())
(append-map (lambda (x)
(list x (cons (car lst) x)))
(powerset (cdr lst)))))
(Thanks to samth for reminding me that flatmap is called append-map in Racket!)
You can just use side effect:
(define res '())
(define
(pow raw leaf)
(cond
[(empty? raw) (set! res (cons leaf res))
res]
[else (pow (cdr raw) leaf)
(pow (cdr raw) (cons (car raw) leaf))]))
(pow '(1 2 3) '())

Iterative map in scheme

I am watching SICP video lectures and i came to a section where tutors are showing procedures to work with lists, so, here is one of them:
(define (map p l)
(if (null? l)
(list)
(cons (p (car l))
(map p (cdr l)))))
What i want to ask is: is there a way to define map in iterative way, or that cons requires lazy evaluation to be executed right?
You original code is almost tail recursive.. the only thing that makes it not is the cons part. If Scheme had equal requirement for having TRMC optimization as it has TCO requirement you could leave your code as is and the implementation would have made it tail recursive for you.
Since it isn't a requirement we need to do our own TRMC optimization. Usually when iterating a list in a loop and having it tail recursive by using an accumulator you get the result in the opposite order, thus you can do linear update reverse:
(define (map proc lst)
(let loop ((lst lst) (acc '()))
(cond ((null? lst) (reverse! acc) acc)
(else (loop (cdr lst)
(cons (proc (car lst)) acc))))))
Or you can do it all in one pass:
(define (map proc lst)
(define head (list 1))
(let loop ((tail head) (lst lst))
(cond ((null? lst) (cdr head))
(else (set-cdr! tail (list (proc (car lst))))
(loop (cdr tail) (cdr lst))))))
Now in both cases you mutate only the structure the procedure has itself created, thus for the user it might as well be implemented in the same manner as your example.
When you use higher order procedures like map from your implementation it could happen it has been implemented like this. It's easy to find out by comparing performance on the supplied map with the different implementations with a very long list. The difference between the executions would tell you if it's TRMCO or how the supplied map probably has been implemented.
You need to embrace recursion in order to appreciate SICP and Scheme in general, so try to get used to it, you will appreciate it later, promised.
But yes, you can:
(define (iterative-map f lst)
(define res null)
(do ((i (- (length lst) 1) (- i 1))) ((= i -1))
(set! res (cons (f (list-ref lst i)) res)))
res)
(iterative-map (lambda (x) (+ x 1)) '(1 3 5))
=> '(2 4 6)
but using set! is considered bad style if avoidable.
In Racket you have a different set of loops that are more elegant:
(define (for-map f lst)
(for/list ((i lst))
(f i)))
(for-map add1 '(1 3 5))
=> '(2 4 6)

how to write a reduce-per-key function in scheme?

"define a procedure 'reduce-per-key' which a procedure reducef and a list of associations in which each key is paired with a list. The output is a list of the same structure except that each key is now associated with the result of applying reducef to its associated list"
I've already written 'map-per-key' and 'group-by-key' :
(define (map-per-key mapf lls)
(cond
[(null? lls) '()]
[else (append (mapf (car lls))(map-per-key mapf (cdr lls)))]))
(define (addval kv lls)
(cond
[(null? lls) (list (list (car kv)(cdr kv)))]
[(eq? (caar lls) (car kv))
(cons (list (car kv) (cons (cadr kv) (cadar lls)))(cdr lls))]
[else (cons (car lls)(addval kv (cdr lls)))]))
(define (group-by-key lls)
(cond
[(null? lls) '()]
[else (addval (car lls) (group-by-key (cdr lls)))]))
how would I write the next step, 'reduce-per-key' ? I'm also having trouble determining if it calls for two arguments or three.
so far, I've come up with:
(define (reduce-per-key reducef lls)
(let loop ((val (car lls))
(lls (cdr lls)))
(if (null? lls) val
(loop (reducef val (car lls)) (cdr lls)))))
however, with a test case such as:
(reduce-per-key
(lambda (kv) (list (car kv) (length (cadr kv))))
(group-by-key
(map-per-key (lambda (kv) (list kv kv kv)) xs)))
I receive an incorrect argument count, but when I try to write it with three arguments, I also receive this error. Anyone know what I'm doing wrong?
Your solution is a lot more complicated than it needs to be, and has several errors. In fact, the correct answer is simple enough to make unnecessary the definition of new helper procedures. Try working on this skeleton of a solution, just fill-in the blanks:
(define (reduce-per-key reducef lls)
(if (null? lls) ; If the association list is empty, we're done
<???> ; and we can return the empty list.
(cons (cons <???> ; Otherwise, build a new association with the same key
<???>) ; and the result of mapping `reducef` on the key's value
(reduce-per-key <???> <???>)))) ; pass reducef, advance the recursion
Remember that there's a built-in procedure for mapping a function over a list. Test it like this:
(reduce-per-key (lambda (x) (* x x))
'((x 1 2) (y 3) (z 4 5 6)))
> '((x 1 4) (y 9) (z 16 25 36))
Notice that each association is composed of a key (the car part) and a list as its value (the cdr part). For example:
(define an-association '(x 3 6 9))
(car an-association)
> 'x ; the key
(cdr an-association)
> '(3 6 9) ; the value, it's a list
As a final thought, the name reduce-per-key is a bit misleading, map-per-key would be a lot more appropriate as this procedure can be easily expressed using map ... but that's left as an exercise for the reader.
UPDATE:
Now that you've found a solution, I can suggest a more concise alternative using map:
(define (reduce-per-key reducef lls)
(map (lambda (e) (cons (car e) (map reducef (cdr e))))
lls))

Scheme sum of list

First off, this is homework, but I am simply looking for a hint or pseudocode on how to do this.
I need to sum all the items in the list, using recursion. However, it needs to return the empty set if it encounters something in the list that is not a number. Here is my attempt:
(DEFINE sum-list
(LAMBDA (lst)
(IF (OR (NULL? lst) (NOT (NUMBER? (CAR lst))))
'()
(+
(CAR lst)
(sum-list (CDR lst))
)
)
)
)
This fails because it can't add the empty set to something else. Normally I would just return 0 if its not a number and keep processing the list.
I suggest you use and return an accumulator for storing the sum; if you find a non-number while traversing the list you can return the empty list immediately, otherwise the recursion continues until the list is exhausted.
Something along these lines (fill in the blanks!):
(define sum-list
(lambda (lst acc)
(cond ((null? lst) ???)
((not (number? (car lst))) ???)
(else (sum-list (cdr lst) ???)))))
(sum-list '(1 2 3 4 5) 0)
> 15
(sum-list '(1 2 x 4 5) 0)
> ()
I'd go for this:
(define (mysum lst)
(let loop ((lst lst) (accum 0))
(cond
((empty? lst) accum)
((not (number? (car lst))) '())
(else (loop (cdr lst) (+ accum (car lst)))))))
Your issue is that you need to use cond, not if - there are three possible branches that you need to consider. The first is if you run into a non-number, the second is when you run into the end of the list, and the third is when you need to recurse to the next element of the list. The first issue is that you are combining the non-number case and the empty-list case, which need to return different values. The recursive case is mostly correct, but you will have to check the return value, since the recursive call can return an empty list.
Because I'm not smart enough to figure out how to do this in one function, let's be painfully explicit:
#lang racket
; This checks the entire list for numericness
(define is-numeric-list?
(lambda (lst)
(cond
((null? lst) true)
((not (number? (car lst))) false)
(else (is-numeric-list? (cdr lst))))))
; This naively sums the list, and will fail if there are problems
(define sum-list-naive
(lambda (lst)
(cond
((null? lst) 0)
(else (+ (car lst) (sum-list-naive (cdr lst)))))))
; This is a smarter sum-list that first checks numericness, and then
; calls the naive version. Note that this is inefficient, because the
; entire list is traversed twice: once for the check, and a second time
; for the sum. Oscar's accumulator version is better!
(define sum-list
(lambda (lst)
(cond
((is-numeric-list? lst) (sum-list-naive lst))
(else '()))))
(is-numeric-list? '(1 2 3 4 5))
(is-numeric-list? '(1 2 x 4 5))
(sum-list '(1 2 3 4 5))
(sum-list '(1 2 x 4 5))
Output:
Welcome to DrRacket, version 5.2 [3m].
Language: racket; memory limit: 128 MB.
#t
#f
15
'()
>
I suspect your homework is expecting something more academic though.
Try making a "is-any-nonnumeric" function (using recursion); then you just (or (is-any-numeric list) (sum list)) tomfoolery.

Scheme Recursively going through a List

Just trying to get back into the swing of scheme again, because everyone loves recursion.. (mhhmnmm.)
anyways trying to return #t or #f to determine whether all elements in a list are unique.
Comparing 1st element and 2nd element no problem. It's recursively continuing..
(define (unique ls)
(if (null? ls) #t
(equal? (car ls)(car(cdr ls)))))
I'll write a different, simpler function that demonstrates looping. Hopefully between that and what you have, you'll get there. :-)
(define (member x lst)
(cond ((null? lst) #f)
((equal? x (car lst)) lst)
(else (member x (cdr lst)))))
Another example:
(define (assoc x alist)
(cond ((null? alist) #f)
((equal? x (caar alist)) (car alist))
(else (assoc x (cdr alist)))))
Well your (equal?) invocation is incomplete. If the head and head-of-the-tail are equal, then the value of "unique" is false. If they're not equal, then you'd return the value of unique as applied to the tail (cdr) of the list.
(It's implicit in your proto-implementation that you're checking a pre-sorted list. If not, then that's another step to take.)
(use srfi-1)
(define (unique? ls) (eq? (length ls) (length (delete-duplicates ls))))

Resources