Scheme - find most deeply nested lists - scheme

I need to find the leaves in a list in Scheme.
For example, if I have (1 (2 3) (4 (5) (7 (8) (10 11 12)))))), my leaves are (8) and (10 11 12). So my function will return (1 (2 3) (4 (5) (7 leaf1 leaf2))))).
Definition: a leaf is an element with the deepest nesting possible.
Examples: In (1 (2 (3))) the element (3) is a leaf.
In ((1 2) (3 4)) the elements (1 2) and (3 4) are leaves.
I tried to use the map function, that will check if the list is composed from lists. If it is - so I call the function again, and if not, I break and change the lists to symbols of leafs. It doesn't work.
I have been stuck on it for 2 days. I am trying to find an idea, not an implementation. Thanks.

This is a little tricky to get right. Here are a few suggestions on one way to do it:
As stated, the problem is to walk the list, finding the most deeply nested lists that don't contain any other lists (these are sometimes called "lists of atoms"), and replacing them with something else. It's possible to do this in one recursive function, but I think it's clearer to break it up into parts:
First, we need a predicate (a function that returns a boolean #t or #f) to determine whether a list is a list of atoms. (This is sometimes called lat?). You can write this as a simple recursive function, or you could use the library functions any and list?
Then we need a function (define (max-lat-depth lst) ...) to find how deeply nested the most-deeply-nested list of atoms in its argument is. This will be a doubly recursive function -- it needs to check the first of each list as well as all the elements in the rest. We can define max-lat-depth as follows:
a. If the argument is a lat itself, the maximum depth is zero, so (max-lat-depth '(1 2 3)) == 0
b. If the first element of the argument isn't a list, it can't affect the maximum nesting depth overall. So in this case the max-lat-depth of the whole argument will be the same as the max-lat-depth of the rest (cdr) of the list: (max-lat-depth '(1 (2 (3 4))) == (max-lat-depth '((2 (3 4))) == 2
c. The tricky case: if the first element of the argument is a list (as in ((1 2) (3 4))), we'll need to recur on both the first (or car) and rest (or cdr) of lst, returning the maximum of these values. However, we need to add 1 to one of these two results before taking the maximum. I'll let you figure out which one and why.
Finally, we write a function (define (replace-lats-at-depth depth lst r) ...) that will take a nesting depth as returned from max-lat-depth, a list lst, and a replacement r. It will return a copy of lst where all the lists-of-atoms at depth depth have been replaced by r. For example:
(replace-lats-at-depth 0 '(1 2 3) '*) == '*
(replace-lats-at-depth 1 '(1 (2) 3) '*) == '(1 * 3).
Like max-lat-depth, replace-lats-at-depth recurs on both the first and rest of lst. It will call cons on the result of its recursive calls to construct a new tree structure. Also like max-lat-depth, it has several cases, and it will need to subtract 1 from depth in one of its recursive calls.
Once you have replace-lats-at-depth working to replace the nested lists with a constant value r, it shouldn't be too hard to improve it with a function that produces leaf1, leaf2, etc. as in your original example.
I hope that's helpful without saying too much. Let me know if not and I can try to clarify.

Related

Vector in scheme

From the documentation of equals? in Racket:
Equal? recursively compares the contents of pairs, vectors, and strings, applying eqv? on other objects such as numbers and symbols. A rule of thumb is that objects are generally equal? if they print the same. Equal? may fail to terminate if its arguments are circular data structures.
(equal? 'a 'a) ===> #t`
(equal? '(a) '(a)) ===> #t`
What exactly is a vector in scheme? For example, is (1. 2) a vector? Is (1 2) a vector? Is (1 2 3 4) a vector? etc.
The docs list the mention of vector and vector? etc, but I'm wondering if they just use vector to mean "list" or something else: https://people.csail.mit.edu/jaffer/r5rs/Disjointness-of-types.html#Disjointness-of-types
A vector is, well, a vector. It's a different data structure, similar to what we normally call an "array" in other programming languages. It comes in two flavors, mutable and immutable - for example:
(vector 1 2 3) ; creates a mutable vector via a procedure call
=> '#(1 2 3)
'#(1 2 3) ; an immutable vector literal
=> '#(1 2 3)
(vector-length '#(1 2 3))
=> 3
(vector-ref '#(1 2 3) 1)
=> 2
(define vec (vector 1 2 3))
(vector-set! vec 1 'x)
vec
=> '#(1 x 3)
You might be asking yourself what are the advantages of a vector, compared to a good old list. Well, that mutable vectors can be modified it in place, and accessing an element given its index is a constant O(1) operation, whereas in a list the same operation is O(n). Similarly for the length operation. The disadvantage is that you cannot grow a vector's size after it's created (unlike Python lists); if you need to add more elements you have to create a new vector.
There are lots of vector-specific operations that mirror the procedures available for lists; we have vector-map, vector-filter and so on, but we also have things like vector-map! that modify the vector in-place, without creating a new one. Take a look at the documentation for more details!

Implementing a math formula in Scheme (DrRacket)

Let me start off by saying that I am a complete novice when it comes to Scheme/Racket. I am trying to implement the following formula:
αi = (3/h)((ai+1 – ai) – (ai – ai-1))
Here is how I've defined my function:
(define alpha_values (lambda (y_values h n) (...))
What I would like it to do is to run the function with a list of y_values along with some constant h and a number n, then compute and return a list of α values. n will go from 1 to n-1, so the first and last element of the list are not going to be iterated upon.
For example, if the list of y_values is '(2 4 6 8) and h is 1 and n is 3 then there should be two α values returned: one for i=1 (y=4), and one for i=2 (y=6), like so: 3*((6-4)-(4-2)) = 0 and 3*((8-6)-(6-4)) = 0 returns '(0 0) for α.
Truthfully, I'm lost as to how to even begin to implement this. I thought about using map but I don't know if it's possible to skip the first and last element while doing so. I've tried doing so recursively using car and cdr but I ran into the issue of "losing" an element in the list needed for the calculation when recursively calling the function again without the first element. I would appreciate some insight as to how to approach the implementation of this formula – not an answer, just an idea as to how to get the ball rolling.
Whenever you are unsure about how to approach a particular problem, consider breaking it down to smaller tasks that are easier to manage, think about, and implement.
For example, going backwards from the end result, you want to produce a list of alphas, whereby each alpha is created from h and an interval {a_i-1, a_i, a_i+1} using the noted formula.
So one small function you can create would be the function, lets call it compute-alpha, that takes an interval and h as arguments, then produces an alpha using the formula. Ie:
(define (compute-alpha interval h)
...)
The body of this function will simply be the formula, and it will behave as follows:
> (compute-alpha '(2 4 6) 1)
0
> (compute-alpha '(4 6 8) 1)
0
But then you realize that you don't have the intervals (eg. '(2 4 6), '(4 6 8) etc) in order to use compute-alpha. So next step is to define another small function, lets call it build-intervals, that takes y-values and n as arguments, and produces a list of intervals. Ie:
(define (build-intervals y-values n)
...)
and behaves as follows:
> (build-intervals '(2 4 6 8) 3)
'((2 4 6) (4 6 8))
> (build-intervals '(1 2 3 4 5 6 7) 4)
'((1 2 3) (2 3 4) (3 4 5))
Now, all that is left is applying compute-alpha on every interval produced by build-intervals. And this is where map shines:
(define (alpha-values y-values h n)
(map (lambda (interval)
(compute-alpha interval h))
(build-intervals y-values n)))
Then you can have:
> (alpha-values '(2 4 6 8) 1 3)
'(0 0)
Once you implement build-intervals and compute-alpha, you might notice ways of combining them to reduce alpha-values to a single function that iterates y-values only once before producing the list of alphas.

relation between foldr and append in Scheme

try to figure out how to use "append" in Scheme
the concept of append that I can find like this:
----- part 1: understanding the concept of append in Scheme-----
1) append takes two or more lists and constructs a new list with all of their elements.
2) append requires that its arguments are lists, and makes a list whose elements are the elements of those lists. it concatenates the lists it is given. (It effectively conses the elements of the other lists onto the last list to create the result list.)
3) It only concatenates the top-level structure ==> [Q1] what does it mean "only concatenates the top-level"?
4) however--it doesn't "flatten" nested structures.
==> [Q2] what is "flatten" ? (I saw many places this "flatten" but I didn't figure out yet)
==> [Q3] why append does not "flatten" nested structures.
---------- Part 2: how to using append in Scheme --------------------------------
then I looked around to try to use "append" and I saw other discussion
based on the other discussion, I try this implementation
[code 1]
(define (tst-foldr-append lst)
(foldr
(lambda (element acc) (append acc (list element)))
lst
'())
)
it works, but I am struggling to understand that this part ...(append acc (list element)...
what exactly "append" is doing in code 1, to me, it just flipping.
then why it can't be used other logics e.g.
i) simply just flip or
iii).... cons (acc element).....
[Q4] why it have to be "append" in code 1??? Is that because of something to do with foldr ??
again, sorry for the long question, but I think it is all related.
Q1/2/3: What is this "flattening" thing?
Scheme/Lisp/Racket make it very very easy to use lists. Lists are easy to construct and easy to operate on. As a result, they are often nested. So, for instance
`(a b 34)
denotes a list of three elements: two symbols and a number. However,
`(a (b c) 34)
denotes a list of three elements: a symbol, a list, and a number.
The word "flatten" is used to refer to the operation that turns
`(3 ((b) c) (d (e f)))
into
`(3 b c d e f)
That is, the lists-within-lists are "flattened".
The 'append' function does not flatten lists; it just combines them. So, for instance,
(append `(3 (b c) d) `(a (9)))
would produce
`(3 (b c) d a (9))
Another way of saying it is this: if you apply 'append' to a list of length 3 and a list of length 2, the result will be of length 5.
Q4/5: Foldl really has nothing to do with append. I think I would ask a separate question about foldl if I were you.
Final advice: go check out htdp.org .
Q1: It means that sublists are not recursively appended, only the top-most elements are concatenated, for example:
(append '((1) (2)) '((3) (4)))
=> '((1) (2) (3) (4))
Q2: Related to the previous question, flattening a list gets rid of the sublists:
(flatten '((1) (2) (3) (4)))
=> '(1 2 3 4)
Q3: By design, because append only concatenates two lists, for flattening nested structures use flatten.
Q4: Please read the documentation before asking this kind of questions. append is simply a different procedure, not necessarily related to foldr, but they can be used together; it concatenates a list with an element (if the "element" is a list the result will be a proper list). cons just sticks together two things, no matter their type whereas append always returns a list (proper or improper) as output. For example, for appending one element at the end you can do this:
(append '(1 2) '(3))
=> '(1 2 3)
But these expressions will give different results (tested in Racket):
(append '(1 2) 3)
=> '(1 2 . 3)
(cons '(1 2) '(3))
=> '((1 2) 3)
(cons '(1 2) 3)
=> '((1 2) . 3)
Q5: No, cons will work fine here. You wouldn't be asking any of this if you simply tested each procedure to see how they work. Please understand what you're using by reading the documentation and writing little examples, it's the only way you'll ever learn how to program.

Comparing items in a list?

If you have a list ( (1 4 5) 5 (6 2 5) ), and another list (5 1 3 7 5 (9 2 4) ), I need to write a procedure that compares items from the first list and sees if they're in the second. For example, (1 4 5) appears 0 times in (5 1 3 7 5 (9 2 3) ). 5 appears in this list 2 times, and (9 2 4) appears 0 times. So the list will return (0 2 0)
I need help writing a scheme procedure frequency that takes in two lists, the first being the one that has each component compared, and the second being the one that counts the number of occurrences of the first list. The procedure should return a list of the occurrences.
Thanks!
This is clearly a homework, so I won't give you a straight answer. Instead, I'll point you in the right direction. For starters, split the problem in two procedures:
The first procedure, let's call it counter, receives an element and a list of elements. It traverses the list of elements asking, for each of them, if it's equal to the element passed as parameter. It adds one to the accumulated result if a match is found or continues with the next element if not. The list traversal ends when the null list is reached, and for this the counter returns zero.
The second procedure, called frequency receives the two lists in the question and traverses the first list (the list of elements to compare against). For each of those elements, it calls counter to find out the result, building up a list along the way.
Here's the general structure of the solution, you must fill-in the blanks:
(define (counter ele lst)
(cond ((null? lst)
<???>)
((equal? ele <???>)
(<???> (counter ele <???>)))
(else
(counter ele <???>))))
(define (frequency els lst)
(if (null? els)
<???>
(cons <???>
(frequency <???> lst))))
Notice that in counter I'm assuming that the element is being searched at the base level in the list, for instance this won't find the element:
(counter 5 '((5)))
=> 0
If you have to find matches like the one on the above example, then the problem is a bit more interesting - you'll need to recursively traverse the list of lists in a tree-like fashion. There are countless examples of that in Stack Overflow or elsewhere in Internet; if you're feeling a bit lost I'd recommend you take a look at either The Little Schemer or How to Design Programs, both books will teach you how to grok recursive processes in general.
usually i would solve this with a method in the template list
template<class t>
class list
{
bool contains( t obj )
{
for( int i = 0; i < this->size; i++ )
if( this->at(i) == obj )
return true;
}
}
i hope this will help you ;)

Why do you have to cons with a null to get a proper list in scheme?

I realize this is a total n00b question, but I'm curious and I thought I might get a better explanation here than anywhere else. Here's a list (I'm using Dr. Scheme)
> (list 1 2 3)
(1 2 3)
Which I think is just sugar for this:
> (cons 1 (cons 2 (cons 3 null)))
(1 2 3)
This, on the other hand, does something else:
> (cons 1 (cons 2 3))
(1 2 . 3)
My questions is, why is that different? What's the point of requiring the null at the end of the list?
The definition of a list is recursive.
1. The null list (empty list) is a list
2. A list is made up of an item cons a list
So these are lists:
1. null => () --read as empty list
2. cons 3 null => (3)
3. cons2 (cons 3 null) => (2, 3)
The last example you gave cons 2 3 does not conform to this list definition so its not a list. That is cons accepts an item and a list. 3 is not a list.
cons adds a new element to the beginning of a list, so what you're doing when you write:
(cons 1 (cons 2 (cons 3 null)))
is recursively adding items to an ever-growing list, starting with null, which is defined to be the empty-list (). When you call (cons 2 3) you're not starting with the empty list to begin with, so are not constructing a list by appending 2 to its beginning.
Lisps, including Scheme, are dynamically typed, and 'the lisp way' is to have many functions over a single data structure rather than different data structures for different tasks.
So the question "What's the point of requiring the null at the end of the list?" isn't quite the right one to ask.
The cons function does not require you to give a cons object or nil as its second argument. If the second argument is not a cons object or nil, then you get a pair rather than a list, and the runtime doesn't print it using list notation but with a dot.
So if you want to construct something which is shaped like a list, then give cons a list as its second argument. If you want to construct something else, then give cons something else as its second argument.
Pairs are useful if you want a data structure that has exactly two values in it. With a pair, you don't need the nil at the end to mark its length, so it's a bit more efficient. A list of pairs is a simple implementation of a map of key to value; common lisp has functions to support such property lists as part of its standard library.
So the real question is "why can you construct both pairs and lists with the same cons function?", and the answer is "why have two data structures when you only need one?"
A cons statement is used to allocate a pair whose car is obj1 and whose cdr is obj2
(cons obj1 obj2)
Therefore, it is necessary to end a cons statement with a null so that we know we are the end of the list.
> (cons 1 (cons 2 3))
(1 2 . 3)
In that example, the cdr would be a pair <2,3> where 2 is the car and 3 is the cdr. Not the same as:
(list 1 2 3)

Resources