Hello, I’m new to Scheme.
I’m reading tutorials on the web, and I wonder how I could count occurrences of atoms in nested lists in Scheme. I found some tutorials mentioning bagify and flatten; I tried to mix them but I got an error. What could be wrong?
Here’s the code:
(define (bagify lst)
(foldl (lambda (key ht)
(hash-update ht key add1 0))
#hash() lst))
(define (flatten mylist)
(cond ((null? mylist) '())
((list? (car mylist)) (append (flatten (car mylist)) (flatten (cdr mylist))))
(else (cons (car mylist) (flatten (cdr mylist))) (bagify(mylist)))))
I think
bagifyandflattenare red herrings for this kind of problem. Sure, you could useflatten, and then count the occurrences in the resulting flattened list. However, it’s much more efficient and straightforward to just traverse the nested list.For simplicity, let’s start by implementing the function for the non-nested case. Here’s a version that counts occurrences of
'?, for even more simplicity:Changing this to work on nested lists just requires adding one
condline. The implementation offlattenyou found contains a hint here: we want to check at each step of the recursion whether thecarof the list is itself a list (However, usinglist?is more power than we need; we can usepair?instead, as long as our input is always a proper, nested list).Once we know the
caris also a (potentially-nested) list, we need to pass it to a function that knows how to handle lists. Fortunately, we’re in the middle of defining one!And that’s all there is to it. Very little thought involved, no? So little, in fact, that you can just replace a couple expressions and wind up with a function that does something completely different to the nested list:
Solving a problem for a nested list is really easy once you’ve solved it for a flat list.
car.carand thecdr.null?case, e.g.,+/0,*/1,cons/'(),and/#t,or/#f.