Hi I'm trying to learn Scheme and I was working on an example from a university website:
https://courses.cs.washington.edu/courses/cse341/05au/lectures/scheme-side-effects.html
The example is something along these lines:
(define circ '(a b))
(set-cdr! (cdr circ) circ)
and this is the output:
=> #0=(a b . #0#)
I don't understand what this means. The code defines a variable called circ as a list with 2 elements (a b).
set-cdr! mutates the cdr of this list [which is (b '())] and changes it to circ (which is (a b)).
So the output I expected here was (a (a b)) but I got this weird hashtag thing instead.
I'm using DrRacket IDE with R5RS scheme set as the language.
What does this hashtag stuff mean? Is it maybe creating a pointer to itself like (a [pointer to circ]) in which case it would be like some kind of infinite loop or something?
I mean if I do this:
(define x '(a b))
(set-cdr! x 'c)
x
=>(a . c) ; is the output
this is easy to understand as set-cdr! replaces the (b '()) with 'c and getting rid of the '() at the end is why I get a dotted pair back instead of a list. But this isn't in-line with the earlier example.
anyway if anybody cares to fill me in, let me know. Thanks in advance.
You are correct in thinking that the operation is the creation of a circular list.
Drawing a list through its cons cells, this is the situation after the define:
and this is the situation after the set-cdr!:
Note that the modification is on the cdr of the cdr of circ (so on the cdr of the second cell). The notation #0=(a b . #0#) in lisp languages describes an improper list where the last cdr is equal to the list itself, producing a circular data structure (i.e. a data structure with a “loop”).
Related
In The Little Schemer (4th Ed.) it is claimed that a list for which null? is false contains at least one atom, or so I understand from my reading of the text.
This doesn't make sense to me, since (atom '()) is false, and we can stick those into a list to make it non-null:
> (null? '(()))
#f
So my question is, is this a mistake in my reading, or a matter of definitions? Since it's not in the errata I assume such a well-studied book wouldn't have a mistake like this.
If we considered (()) to be the same as (() . ()) or even (cons '() '()) and then considered cons an atom then I could see how you can get there, but I don't think that's what's going on.
(this was tested in Racket 7.0, with the definition of atom? given in the book, i.e.
(define atom?
(lambda (x)
(and (not (pair? x)) (not (null? x)))))
I know this doesn't cover funny Racket features, but should be sufficient here.)
lat is assumed to be a list of atoms at that point in the book.
If it's not empty, by definition it contains some atoms in it.
It's not about Lisp, it's about the book's presentation.
I think lat indicates list of atoms. Thus if lat is not null?, then it needs to contain at least one atom.
There is a procedure called lat? defined as such:
(define lat?
(lambda (l)
(cond
((null? l) #t)
((atom? (car l))
(lat? (cdr l)))
(else #f))))
(lat? '(()) ; ==> #f so by definition '(()) is not a lat and thus the statement does not apply to that list.
A list can contain any type of elements, including empty and other lists, both which are not atoms. lat is a restricted to a flat list with only atomic elements.
As a concept an “atom” is something that can not be broken into smaller parts. A number 42 is an atom, a list (42 43) is not an atom since it contains two smaller parts (namely the numbers 42 and 43). Since an empty list does not contain any smaller parts, it is by this logic an atom.
Now let’s attempt to implement an atom? predicate, that determines whether it’s input is an atom.
(define (atom? x)
(cond
[(number? x) #t]
[(symbol? x) #t]
[(char? x) #t]
...
[else #f]))
Here the ... needs to be replaced with a test for every atomic data type supported by the implementation. This can potentially be a long list. In order to avoid this, we can try to be clever:
(define (atom? x)
(not (list? x)))
This will correctly return false for non-empty lists, and true for numbers, characters etc. However it will return false for the empty list.
Since it is up to the authors of the book to define the term “atom” (the word does not appear in the language standard) they might have opted for the above simple definition.
Note that the definition as non-list is misleading when the language contains other compound data structures such as vectors and structures. If I recall correctly the only compound data structure discussed in the book is lists.
I've read and somewhat understand Use of lambda for cons/car/cdr definition in SICP. My problem is understanding the why behind it. My first problem was staring and staring at
(define (cons x y)
(lambda (m) (m x y)))
and not understanding how this function actually did any sort of consing. Consing as I learned it from various Lisp/Scheme books is putting stuff in lists, i.e.,
(cons 1 ()) => (1)
how does
(define (cons x y)
(lambda (m) (m x y)))
do anything like consing? But as the light went on in my head: cons was only sort of a placeholder for the eventual definitions of car and cdr. So car is
(define (car z)
(z (lambda (p q) p)))
and it anticipates an incoming z. But what is this z? When I saw this use:
(car (cons 1 2))
it finally dawned on me that, yes, the cons function in its entirety is z, i.e., we're passing cons to car! How weird!
((lambda (m) (m 1 2)) (lambda (p q) p)) ; and then
((lambda (p q) p) 1 2)
which results in grabbing the first expression since the basic car operation can be thought of as an if statement where the boolean is true, thus, grab the first one.
Yes, all lists can be thought of as cons-ed together expressions, but what have we won by this strangely backward definition? It's as if any initial, stand-alone definition of cons is not germane. It's as if uses of something define that something, as if there's no something until its uses circumscribe it. Is this the primary use of closures? Can someone give me some other examples?
but what have we won by this strangely backward definition?
The point of the exercise is to demonstrate that data structures can be defined completely in terms of functions; that data structures are not necessary as a primitive construct in a language -- if you have functions (that are closures), that's sufficient. This shows the power of functions, and is probably mind-boggling to someone from outside of functional programming.
It's not that in a real project we would actually define data structures this way. It would be more efficient to use language-provided data structure constructs. But it's important to know that we can do it this way. In computer science, it's useful to be able to "reduce" one construct (data structures) into another construct (functions) so that if we prove something about the second construct, it applies to the first one too.
I have an assignment question that asks me to write a function, using lambda, that consumes a list of numbers and removes all but the first occurrence of each number. My function is I think quite nice, with the exception that it produces the wrong result! It produces a list that contains the last occurrence of each number. It produces a list with the same values as the proper list, just in different order. Here's my code:
(define (remove-duplicates numlist)
(foldr (lambda (a b)
(cond
[(not (member? a b)) (cons a b)]
[else b])) empty numlist))
I've tried using foldl instead of foldr but, not surprisingly, it produces the correct list, but in reverse. Is there a way of producing the correct list without resorting to reversing the list created by foldl with another lambda expression?
Please keep in mind, this is homework so no explicit answers please.
Thanks everyone!
Think about how foldr behaves, semantically. It starts at the rightmost element of the list, and performs the fold, moving leftwards. That means that in your lambda function, a represents the element directly to the left of the thus-far-folded list, and b represents the result of folding everything to the right of the list element a. With this in mind, consider:
[(not (member? a b)) (cons a b)]
[else b]
You check whether the list b already contains a. If it does, then you discard a, keeping b as it is. This explains why your code keeps the last (rightmost) occurrence, and not the first. If you wish to perform a right fold, then, you must change your logic. You need to somehow "purge" b of the offending element a that it contains.
[(not (member? a b)) (cons a b)]
[else (cons a (purge a b))]
This way, you will eventually keep only the leftmost, rather than the rightmost, occurrence of each unique element. It may be wise to perform member? and purge simultaneously, since they both must traverse the list; this would require additional refactoring.
Note that, since the function takes O(n2) time anyways, it really doesn't hurt the time complexity to add a O(n) reverse to the foldl version.
I am having trouble writing a function that will move the first element to the end of the list every time it is called. I have tried using a combination of reverse and cdr to cut off the elements at either end, but cannot figure out how to add the elements to the correct end. Any help would be appreciated. Thanks!
Correct outcomes:
(first_to_last '(1 2 3))
(2 3 1)
(first-to-last (first-to-last '(1 2 3)))
(3 1 2)
I think you're over-doing the reversing, personally.
What we want is a list consisting of cdr x with car x appended to the end. The one trick here is that car x isn't a list, so we want to convert it to a list before appending it:
(define (first-to-last x) (append (cdr x) (list (car x))))
If you wanted to stick to the fundamentals, cons is the really fundamental way to put things together into lists, but it would be a bit more work. You'd basically end up defining something essentially identical to append in terms of cons. That's pretty easy but kind of pointless, given that append already exists.
Edit: I guess if you want to use reverse for some reason or other, you could do something like this:
(define (first-to-last x) (reverse (cons (car x) (reverse (cdr x)))))
It's a bit longer and strikes me as kind of clumsy, but it ought to work anyway.
Finally taking the plunge to learn a Lisp dialect (Scheme), I have encountered two definitions of a list -
"Either the empty list or a pair whose cdr is a list".
"A collection of S-Expressions enclosed by parentheses".
Are these definitions equivalent?
They're as equivalent as {'a','b','c'} and "abc"
The former is the machine's logical representation of a list, the latter is how you represent it in your code.
And in scheme, you can pretty much treat everything as a list :) (Someone's going to downvote me for that, but I found it to be true when trying to think scheme-esque.)
I'm going to bring out my favourite dog-and-pony show!
(source: hedgee.com)
This corresponds to the following:
(let ((s5 (sqrt 5)))
(/ (- (expt (/ (1+ s5) 2) n)
(expt (/ (- 1 s5) 2) n)) s5))
The diagram illustrates your first statement (the empty-list object is denoted as a black box). The code snippet illustrates your second. :-)