I'm trying to use this:
(vector-set! (vector-ref array (car xy)) (cdr xy) step_count)
where xy is a list like '(0 0) passed in as a parameter.
But I get this error:
vector-set!: contract violation
expected: exact-nonnegative-integer?
given: '(0)
argument position: 2nd
other arguments...:
'#(0 0 0 0 0)
1
There is a problem with (cdr xy), I think I need to turn '(0) into 0 but I can't find a mechanism in Racket that can do that.
I know a line like this:
(vector-set! (vector-ref array (sub1 (car xy))) (sub1 (cdr xy)) (read))
works when you form xy with:
(define xy (cons (read) (read)))
Can someone point me in the right direction?
Thanks for reading.
When you use cdr on a list, it means "the rest of the list". The rest of a list is always a list, not a single element of a list.
If you want the second element of the list xy, then you need to use cadr.
(You could also use second.)
(define xy (list 1 2 3))
(cdr xy) ; '(2 3)
(cadr xy) ; 2
(second xy) ; 2
Related
In the following code:
(define l (cons 1 2))
l
(list? l)
(pair? l)
(list-ref l 0) ; works;
(list-ref l 1) ; DOES NOT WORK;
Output:
'(1 . 2)
#f
#t
1
Error: list-ref: index reaches a non-pair
index: 1
in: '(1 . 2)
Why (list-ref l 0) works if l is not a list. Otherwise, why (list-ref l 1) does not work. This behavior seems to be inconsistent and confusion creating.
The functions car and cdr also work, returning 1 and 2, respectively. Why should cdr work if this is not a list. One would expect car to return 1.2 and not just 1.
From the documentation:
The lst argument need not actually be a list; lst must merely start with a chain of at least (add1 pos) pairs.
This means the lst argument is allowed to be an improper list as long as the index is smaller than the index of the first pair whose cdr is a non-pair.
A list is simply a lot of pairs linked together terminating in an empty list. For example, (list 1 2 3) is equivalent to (cons 1 (cons 2 (cons 3 '()))).
There's no reason to loop through the entire list to check if l is a list, so as long as it looks like a list, scheme doesn't care if it terminates in an empty list. list-ref is basically defined as so:
(define (list-ref lyst index)
(cond ((= index 0) (car index))
(else (list-ref (cdr lyst) (- index 1)))))
So of course it will encounter an error when it tries to run (car 2)
As for the other question, car and cdr simply return the first element in a pair and the second element in a pair respectively.
I have a circular list, eg: #0=(1 2 3 4 . #0#).
What I want to do is to insert a new element (x) into this list so that the outcome is #0=(x 1 2 3 4 . #0#). I have been trying using this code (x is the circular list):
(define (insert! elm)
(let ((temp x))
(set-car! x elm)
(set-cdr! x temp)))
However, I think that set-cdr! is not working like I want it to. What am I missing here? Maybe I am way off?
The easiest way to prepend an element to a list is to modify the car of the list, and set the cdr of the list to a new cons whose car is the original first element of the list and whose cdr is the original tail of the list:
(define (prepend! x list) ; list = (a . (b ...))
(set-cdr! list (cons (car list) (cdr list))) ; list = (a . (a . (b ...)))
(set-car! list x)) ; list = (x . (a . (b ...)))
(let ((l (list 1 2 3)))
(prepend! 'x l)
(display l))
;=> (x 1 2 3)
Now, that will still work with circular lists, because the cons cell (i.e., pair) that is the beginning of the list remains the same, so the "final" cdr will still point back to object that is the beginning. To test this, though, we need some functions to create and sample from circular lists, since they're not included in the language (as far as I know).
(define (make-circular list)
(let loop ((tail list))
(cond
((null? (cdr tail))
(set-cdr! tail list)
list)
(else
(loop (cdr tail))))))
(define (take n list)
(if (= n 0)
'()
(cons (car list)
(take (- n 1)
(cdr list)))))
(display (take 10 (make-circular (list 1 2 3))))
;=> (1 2 3 1 2 3 1 2 3 1)
Now we can check what happens if we prepend to a circular list:
(let ((l (make-circular (list 1 2 3))))
(prepend! 'x l)
(display (take 15 l)))
;=> (x 1 2 3 x 1 2 3 x 1 2 3 x 1 2)
Since you're trying to prepend an element to a circular list, you need to do two things:
Insert a new cons cell at the front of the list containing the additional element. This is easy because you can just perform a simple (cons elm x).
You also need to modify the recursive portion of the circular list to point at the newly created cons cell, otherwise the circular portion will only include the old parts of the list.
To perform the latter, you need a way to figure out where the "end" of the circular list is. This doesn't actually exist, since the list is, of course, circular, but it can be determined by performing an eq? check on each element of the list until it finds an element equal to the head of the list.
Creating a helper function to do this, a simple implementation of insert! would look like this:
(define (find-cdr v lst)
(if (eq? v (cdr lst)) lst
(find-cdr v (cdr lst))))
(define (insert! elm)
(set! x (cons elm x))
(set-cdr! (find-cdr (cdr x) (cdr x)) x))
I'm trying to write a function using Scheme that :
take a list of integers with more than two elements as a parameter
sum the n-th-element and (n+1)-th-element
return this list
Result should be as follows :
> (SumNeighbors (list 1 2 3 4))
(3 5 7)
I think I get the way to add elements but my recursion is totally wrong...
(define (SumNeighbors lst)
(if (not (null? (cdr lst)))
(append (list (+ (car lst) (car (cdr lst)))) (SumNeighbors (cdr lst)))))
Any help would be appreciated.
The solution to this problem follows a well-known pattern. I'll give you some hints, it'll be more fun if you find the answer by your own means:
(define (SumNeighbors lst)
(if <???> ; if there's only one element left
<???> ; we're done, return the empty list
(cons ; otherwise call `cons`
(+ <???> <???>) ; add first and second elements
(SumNeighbors <???>)))) ; and advance recursion
Notice the following:
Your solution is lacking the base case - what happens when the list we're traversing only has one element left? it's time to finish the recursion! and because we're building a list as the output, what should be the value returned?
We normally use cons to build an output list, not append. That's the natural way to build a list
The part of this procedure that falls outside the solution template is the fact that we stop when there's a single elment left in the list, not when the list is empty (as is the usual case)
You'll see that many procedures that iterate over an input list and return a list as output follow the same solution template, it's very important that you learn how and why this works, it's the foundation for writing solutions to other similar problems.
#!r6rs
(import (except (rnrs base) map)
(only (srfi :1) map))
(define (sum-neighbors lst)
(map + lst (cdr lst)))
The higher order function map as defined in SRFI-1 supports uneven lenght arguments. It will stop at the shortest list.
If you call (sum-neighbors '(1 2 3 4)) it will become (map + (1 2 3 4) (2 3 4)) which is the same as (cons (+ 1 2) (cons (+ 2 3) (cons (+ 3 4) '())))
How would you define a function which takes one argument, which should be a list, and returns the elements in the
list which are themselves lists?
(check-expect (find-sublists ’(1 2 () (3) (a b c) a b c))
’(() (3) (a b c)))
Do you have experience designing functions that can filter through a list?
A simpler problem with the same flavor as the original is something like this: design a function that takes a list of numbers and keeps only the even numbers. Would you be able to do that function?
Looking at http://www.ccs.neu.edu/home/matthias/HtDP2e/htdp2e-part2.html and going through its guided exercises may also help.
Two useful tools which should start you on your way:
1) Traversing through a list:
; traverse: takes a list of numbers
; Goes through each element, one-by-one, and alters it
(define traverse
(lambda (the_list)
(if (empty? the_list)
empty
(cons (+ 1 (first the_list))
(traverse (rest the_list))))))
(traverse (cons 3 (cons 4 empty))) returns (cons 4 (cons 5 empty))
2) list?:
(list? (list 1 2 3)) returns #t
(list? 5) returns #f
I am trying to write a simple procedure in Lisp to insert an element into binary search tree.
I represented the tree as a list:
the first element in the tree is the root
the second element is the left sub-tree
the third element is the right sub-tree
This is my code:
(define Insert
(lambda (x T)
(if (null? T)
(list x '() '())
(if (> x (car T))
(list (car T)
(cadr T)
(Insert x (list (caddr T))))
(list (car T)
(Insert x (cadr T))
(list (caddr T)))))))
When I call the procedure like this: (Insert 2 '(4 '(2 '() '() ) '())), I get a problem with ">" because the second argument isn't a real number, but I don't know why.
The exception:
>: expects type <real number> as 2nd argument, given: quote; other arguments were: 2
However, when I call the procedure like this: (Insert 2 ( list 4 (list 2 '() '() ) '())),
it works successfully.
Why?
I know that '(1 '() '()) and (list 1 '() '()) are equals, aren't they?
No, quote and list are not the same at all. The meaning of 'foo is (quote foo).
'(a b c) is exactly (quote (a b c)), that is, a list literal (the quote operator prevents the list from being evaluated). It is comparable to "a b c", which is a string literal or 5, which is a number literal. Operations that modify literals have undefined effects, as you may recognize immediately when you see some nonsense like (setf 3 4).
(list a b c), on the other hand, creates ("conses") a new list from the values of a, b, and c.
I am sure that if you clear up your confusion about quote and list, you will be able to correct your code.
'(1 '()) is equivalent to (list 1 (list 'quote nil)). I suspect that if you drop the "internal" quote characters, you will be fine.
So, the quoted expression that generates an expression that is equal to (list 1 '() '()) is '(1 () ()).