Vector in scheme - 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!

Related

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.

Scheme - find most deeply nested lists

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.

SICP Accumulate function

In Structure and Interpretation of Computer Programs (SICP) Section 2.2.3 several functions are defined using:
(accumulate cons nil
(filter pred
(map op sequence)))
Two examples that make use of this operate on a list of the fibonacci numbers, even-fibs and list-fib-squares.
The accumulate, filter and map functions are defined in section 2.2 as well. The part that's confusing me is why the authors included the accumulate here. accumulate takes 3 parameters:
A binary function to be applied
An initial value, used as the rightmost parameter to the function
A list to which the function will be applied
An example of applying accumulate to a list using the definition in the book:
(accumulate cons nil (list 1 2 3))
=> (cons 1 (cons 2 (cons 3 nil)))
=> (1 2 3)
Since the third parameter is a list, (accumulate cons nil some-list) will just return some-list, and in this case the result of (filter pred (map op sequence)) is a list.
Is there a reason for this use of accumulate other than consistency with other similarly structured functions in the section?
I'm certain that those two uses of accumulate are merely illustrative of the fact that "consing elements to construct a list" can be treated as an accumulative process in the same way that "multiplying numbers to obtain a product" or "summing numbers to obtain a total" can. You're correct that the accumulation is effectively a no-op.
(Aside: Note that this could obviously be a more useful operation if the output of filter and input of accumulate was not a list; for example, if it represented a lazily generated sequence.)

Finding keys closest to a given value for clojure sorted-maps

For clojure's sorted-map, how do I find the entry having the key closest to a given value?
e.g. Suppose I have
(def my-map (sorted-map
1 A
2 B
5 C))
I would like a function like
(find-closest my-map 4)
which would return (5,C), since that's the entry with the closest key. I could do a linear search, but since the map is sorted, there should be a way of finding this value in something like O(log n).
I can't find anything in the API which makes this possible. If, for instance, I could ask for the i'th entry in the map, I could cobble together a function like the one I want, but I can't find any such function.
Edit:
So apparently sorted-map is based on a PersistentTreeMap class implemented in java, which is a red and black tree. So this really seems like it should be doable, at least in principle.
subseq and rsubseq are very fast because they exploit the tree structure:
(def m (sorted-map 1 :a, 2 :b, 5 :c))
(defn abs [x] (if (neg? x) (- x) x))
(defn find-closest [sm k]
(if-let [a (key (first (rsubseq sm <= k)))]
(if (= a k)
a
(if-let [b (key (first (subseq sm >= k)))]
(if (< (abs (- k b)) (abs (- k a)))
b
a)))
(key (first (subseq sm >= k)))))
user=> (find-closest m 4)
5
user=> (find-closest m 3)
2
This does slightly more work than ideal, in the ideal scenario we would just do a <= search then look at the node to the right to check if there is anything closer in that direction. You can access the tree (.tree m) but the .left and .right methods aren't public so custom traversal is not currently possible.
Use the Clojure contrib library data.avl. It supports sorted-maps with a nearest function and other useful features.
https://github.com/clojure/data.avl
The first thing that comes to my mind is to pull the map's keys out into a vector and then to do a binary search in that. If there is no exact match to your key, the two pointers involved in a binary search will end up pointing to the two elements on either side of it, and you can then choose the closer one in a single (possibly tie breaking) operation.

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