Why does the following code snippet print nil instead of the last element?
(progn
(setq lst '(3 5 7))
(while (not (equal lst (car lst)))
(setq lst (cdr lst)))
;; BODY
(print lst))
Note: I need to process the last element differently than the rest of the list.
Because the cdr of the last element is nil, and you are setting the variable to that.
Generally, the car of each cons is a value (which could be a pointer to another list), and the cdr is a pointer to the remainder of the list. So when traversing a list, you usually want to operate on the car.
(progn
(setq lst '(3 5 7))
(while (cdr lst))
(setq lst (cdr lst)))
(print (car lst)))
Any basic Lisp introduction will have better visualizations than I have, but if you have read one, this should look familiar. The basic building block of a list is a cons cell with a car and a cdr (the names are apparently holdovers of register names used in the first Lisp implementations).
+------+------+
| car | cdr |
+------+------+
Your list with three elements will have three conses; (3 . (5 . (7 . nil))) or graphically
+---+---+ +---+---+ +---+---+
| . | o--->| . | o--->| . | o---#
+-v-+---+ +-v-+---+ +-v-+---+
3 5 7
So the car of the first cons is (a pointer to) the value 3, and its cdr is (a pointer to) the next cons in the list.
Related
I am new in Racket and I was assigned to do my own filter procedure. It should work similar to the Racket filter procedure. Currently, my-filter has two arguments: the even procedure to check the items in the list, and a list of items.
So far, I have been only able to check whether the items in the list are even or not. my-filter is supposed to iterate through a list of numbers, retrieve the numbers that are even and save them in a second list. How can I iterate through the list and store the even numbers in the second list?
(define (my-filter f lst)
(if (empty? lst)
empty
(cons
(f (first lst))
(my-filter f (rest lst)))))
> (my-filter even? '(1 2 3 4 5 6))
'(#f #t #f #t #f #t)
There are three cases that you need to consider:
Input list is empty -> we're done.
Current element satisfies the predicate function -> add it to the output and continue with next element.
Current element doesn't satisfy the predicate function -> skip it and continue with next element.
You're mixing the last two cases into a single case. And notice that you must not add (f (first lst)) to the output, that's just the condition that we want to evaluate, we should add (first lst) instead. This is what I mean:
(define (my-filter f lst)
(cond ((empty? lst) empty)
((f (first lst))
(cons (first lst) (my-filter f (rest lst))))
(else (my-filter f (rest lst)))))
It works as expected:
(my-filter even? '(1 2 3 4 5 6))
=> '(2 4 6)
(define (min list)
(cond ((empty? (car list) '"It is empty")) <- Problem is here. Code work without this line.
((empty? (cdr list)) (car list)) ;to check list is empty
((< (car list) (min (cdr list))) (cdr list))
(else (min (cdr list) ))))
I am very new to scheme Programming language. I am trying to get minimum value from the list. When I put (), the program gives me an error: cdr: contract violation expected: pair? given: '(). What I am trying to do here is I want to print out It is empty when user type (). Is it possible do like that in Scheme programming?
You can find the answer to this question--and so much more--in How To Design Programs, 2e, a textbook written by the developers of the Racket language.
In this case, you want to be using the template for functions on lists. This is covered in section II, more specifically section 9.1.
The structure of a list in Scheme and other Lisp-languages is based on cons-cells. Each cons-cell contains a value (the car) and a pointer to the next cons cell (the cdr, pronounced see-dar) in the list, like this:
+-+-+
|1|----+
+-+-+ |
+-+-+
|2|---+
+-+-+ |
+-+-+
|3| |
+-+-+
The final cons-cell, where the list ends, contains a nil. In Scheme notation, a cons-cell looks like this:
(1 . 2)
So a list, without any syntactic sugar, would look like this:
(1 . (2 . (3 . (4 . nil))))
An empty list, consists of a cons cell that looks like this:
(nil)
Notice that the empty list has no car? An empty list is treated like a nil, so this:
(1 . (2 . (3 . (4 . ()))))
Works just like the previous one.
Now, when you use the syntactic sugar, lists look like this:
(1 2 3 4)
But the underlying structure is the same. So, to test if you have an empty list, test if it's nil (which Scheme does with the empty? function). So, instead of calling empty? on the car of the list, which is wrong thinking as well as an error, call it on the list. So your function should look like:
(define (min list)
(cond ((empty? list "It is empty"))
((empty? (cdr list)) (car list))
((< (car list) (min (cdr list))) (cdr list))
(else (min (cdr list) ))))
Notice that the second arm does not check that the list is empty, as your comment says: it checks if the list has only one or no element. If your cdr is empty, but your car isn't (which the second arm allows), then you have a one element list:
(foo . ())
Hope this helps!
For more information on how to improve your specific function, look at Oscar Lopez's answer to this question.
I think you want to print empty list or get min value, right?
(define (min list)
(if (null? list)
"It's empty."
(let loop ([loop_list list]
[min_value (car list)])
(if (null? loop_list)
min_value
(loop
(cdr loop_list)
(if (< min_value (car loop_list)) min_value (car loop_list)))))))
I tried reversing a list in scheme using the most basic concept I had about cons,cdr,car.
Here,l-orig is the list to be reversed and l-count acts as a counter.
My code goes here:
(define (rev l-orig l-count)
(
if (null? l-count)
(cons l-orig '())
(rev (cons (cdr l-orig) (car l-orig)) (cdr l-count))
)
)
(display (rev '(1 2 3 4 5) '(1 1 1 1 1)))
And the output is (((2 3 4 5) . 1))
Honestly speaking, I am a beginner in lisp and I need a simple help here.
If I intend to use this method, can anyone suggest me a correct way of doing it?
You're attempting to reverse a list using tail recursion, with the help of an accumulator parameter. The best way would be to traverse the original list and cons each of its elements at the head of the accumulator, which will be returned at the end:
(define (rev l-orig l-count)
(if (null? l-orig)
l-count
(rev (cdr l-orig) (cons (car l-orig) l-count))))
Notice that the accumulator starts as an empty list, which is perfect for consing each new element to it:
(rev '(1 2 3 4 5) '())
=> '(5 4 3 2 1)
Oscar's answer is right on. You can use a helper function so you don't need to pass in an empty accumulator every time:
(define (rev xs)
(rev-accum xs '()))
(define (rev-accum xs accum)
(if (null? xs)
accum
(rev-accum (cdr xs) (cons (car xs) accum))))
I am busy with Structure and Interpretation of Computer Programs exercise 2.18. Here we have to define a procedure reverse to reverse a list. It should do the following:
(reverse (list 1 4 9 16 25))
;; => (25 16 9 4 1)
I came up with the following definition:
(define (reverse list)
(if (null? list)
list
(cons (reverse (cdr list)) (car list))))
;; => (mcons (mcons (mcons (mcons (mcons '() 25) 16) 9) 4) 1).
Then in a solution In found something similar as follows:
(define (reverse items)
(if (null? (cdr items))
items
(append (reverse (cdr items))
(cons (car items) nil))))
;; => (mcons 25 (mcons 16 (mcons 9 (mcons 4 (mcons 1 '()))))).
There's a difference between append and cons here where I cannot put my finger on.
My question: what is the difference and why are the results not displayed as (25 16 9 4 1)?
Short answer: the first version of reverse is incorrectly building an improper list, the second version is inefficiently building a proper list. We can do better as long as we understand the difference between append and cons.
append concatenates two lists. If we use it for just adding an element at the end of one list, we'll be doing a lot more of work than needed: we'll have to traverse the whole list each time just to put one last element (see: Schlemiel the Painter's algorithm). Hence a reverse implementation that uses append can be as bad as O(n^2) in complexity.
On the other hand, cons adds a single element to the head of a list, for an O(n) complexity in the implementation of reverse. In general, in Scheme you should try to avoid using append to build a new output list, always prefer cons. Now let's see what's being returned by your algorithm using cons:
(reverse '(1 2 3 4 5))
=> '(((((() . 5) . 4) . 3) . 2) . 1)
Why is that? because to build a proper list with cons the second argument must be another proper list, but you're passing a single element. A correct implementation requires an accumulator parameter - and incidentally, this is more efficient, because it uses tail recursion, a concept that you should already be familiar with, as it was introduced in section 1.2 of the book. Try this:
(define (reverse lst acc)
(if (null? lst)
acc
(reverse (cdr lst) (cons (car lst) acc))))
(reverse '(1 2 3 4 5) '())
=> '(5 4 3 2 1)
For the last part of the question: the list is being displayed with mcons (the m means that the cons cells are mutable) because of the language you're using, try switching to #lang racket, which uses immutable cons cells by default, and will get printed as you expect.
I have been listening to Stanford's programming paradigm lecture series, but I'm confused by the following code (from lecture 20). Would someone explain, line by line, what this is doing?
Thanks.
(define (flatten sequence)
(cond ((null? sequence) '())
((list? (car sequence)) (append (flatten (car sequence))
(flatten (cdr sequence))))
(else (cons (car sequence)
(flatten (cdr sequence))))))
# define a procedure 'flatten' that takes a list 'sequence'
(define (flatten sequence)
# if the 'sequence' is empty, return an empty list
(cond ((null? sequence) (list))
# if the first element of 'sequence' is itself a list, return a new list
# made by appending the flattened first element of 'sequence' with the
# flattened rest of the 'sequence'
((list? (car sequence))
(append (flatten (car sequence))
(flatten (cdr sequence))))
# if the first element of 'sequence' is not a list, return a new list
# made by cons-ing that element with the flattened rest of the 'sequence'
(else
(cons (car sequence)
(flatten (cdr sequence))))))
I pretty-printed it (inserted some newlines and indented the code to show its structure) and also replaced '() with (list) (which has the same value) just to prevent the code from being highlighted incorrectly.
+1 what is cons-ing? I'd appreciate if you explain other keywords as well. thanks
When I say cons-ing I'm just referring to the cons procedure. When you see (cons <expression> <list>) where <expression> is any Scheme expression or value and <list> is any Scheme expression that evaluates to a list, cons will return the <list> with the value of the <expression> tacked on the front of it. For example, (cons 1 (list 2 3 4)) returns the list (list 1 2 3 4). In fact, (list 1 2 3 4) in Scheme is just a short way of writing (cons 1 (cons 2 (cons 3 (cons 4 '() )))).
The other two words you might have trouble with are car and cdr. You can think of (car <list>) as meaning the first element or head of the <list>, and (cdr <list>) as meaning the rest of the elements or tail of the <list>. For example, (car (list 1 2 3 4)) returns the value 1, and (cdr (list 1 2 3 4)) returns the list (list 2 3 4).
If you need any help with other keywords, let me know.
define function to flatten a
sequence
For the empty sequence, return empty
if the head (car) of the list is a
sequence return the result of
flattening it appended to the
flattening of the tail (cdr)
else append the head to the flatting
of the tail