Why list-ref works with pair - list

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.

Related

Insert element to circular list using scheme

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))

Using recursion to getNth position for Racket

I have to write a recursive call in Racket that allows us to get the Nth position of a given list. for example (getNth 3 '(1 2 3 4)) should return back 4 and if the list is empty or if the position is non existent then return and empty list.
this is my code:
(define getNth
(lambda (ls)
(if (= ls null?) 1
(getNth ls(append '(car ls)(cdr ls))))))
getting this error:
getnth: arity mismatch;
the expected number of arguments does not match the given number
expected: 1
given: 2
arguments...:
4
()
if you need the recursive statement here it is:
base case-getNth N LS) = (), if LS = null
recursive call -(getNth N LS) = (getNth N (append '(car LS)(cdr LS))), if N >= 1
im getting stumped I dont know how to implement this one.
Assuming your getNth can revieve a "N" from a list (rather than a fixed N i.e. get3rd), your are indeed missing an argument:
(define getNth
(lambda (n list)
(cond ((null? list) '())
((= n 0) (car list))
(else (getNth (- n 1) (cdr list))))))
Which basically is until I get to the number I want, decrement the it and "pop" the first element out until the first element of the list is the one I want i.e. the rest of the list.
Your lambda only takes one argument the way you defined it which is exactly the error message you're having ;)
I think I appropriately balanced my parenthesis :)
A trick with recursion: it's generic concept is easy:
A recusrion is "if a terminal condition occurs, I'm done, return appropriate value. Else, increment the argument toward termination condition and call myself with these new arguments"
It gets complicated when the termination condition can have exceptions. Because if your can't trivially expressed it as "if this done else redo with increment" you could make mistakes...
There are several issues with you code..
You say you need a procedure that takes two arguments, but yours take only ls.
When ls is the empty list the result is 1
if list is not empty you recurse with two arguments, both lists. The first is the same as the original argument which would make a infinite recursion. The second is an append between '(car lst) which evaluates to the list (car lst) and (cdr ls) (the the list ls except the first pair)
(define get-nth
(lambda (index lst)
(if (= index 0) ; when index is zero
(car lst) ; return the first element
(get-nth (- index 1) ; else recurse with the decrement of index
(cdr lst))))) ; and all but the first element (the rest) of lst
;; test
(get-nth 0 '(a)) ; ==> a
(get-nth 1 '(a b)) ; ==> b
;; However, this won't work:
(get-nth 0 '()) ; will fail
(get-nth 10 '(a b c)) ; will fail
I kind of like the fact that it doesn't work when given wrong arguments. list-ref and car fails just as much if gived wrong parameters, but that is easy to fix:
(define get-nth
(lambda (index lst)
(cond ((not (pair? lst)) '()) ; it should always be a pair
((= index 0) (car lst)) ; when index is zero, return the first element
(else (get-nth (- index 1) ; else recurse with the decrement of index
(cdr lst)))))) ; and all but the first element (the rest) of lst
Instead of just th empty list you can have a default value or perhaps throw an error with (raise 'get-nth-error) (R6RS+)

Scheme - Recursion : Sum consecutive elements of a list

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) '())))

functions and lists in scheme/racket

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

what is the 'cons' to add an item to the end of the list?

what's the typical way to add an item to the end of the list?
I have a list (1 2 3) and want to add 4 to it (where 4 is the result of an evaluation (+ 2 2))
(setf nlist '(1 2 3))
(append nlist (+ 2 2))
This says that append expects a list, not a number. How would I accomplish this?
You could use append, but beware that it can lead to bad performance if used in a loop or on very long lists.
(append '(1 2 3) (list (+ 2 2)))
If performance is important, the usual idiom is building lists by prepending (using cons), then reverse (or nreverse).
If the "cons at the front, finish by reversing" idiom isn't suitable for you (if you. for example, need to pass the list on to other functions DURING its construction), there's also the "keep track of the end" trick. However, it's probably cleaner to just build the list by consing to the front of it, then finish by using reverse or nreverse before finally using it.
In essence, this allows you to have the list in the right order while building it, at the expense of needing to keep track of it.
(defun track-tail (count)
(let* ((list (cons 0 nil))
(tail list))
(loop for n from 1 below count
do (progn
(setf (cdr tail) (cons n nil))
(setf tail (cdr tail))
(format t "With n == ~d, the list is ~a~%" n list)))
list))
This gives the following output:
CL-USER> (track-tail 5)
With n == 1, the list is (0 1)
With n == 2, the list is (0 1 2)
With n == 3, the list is (0 1 2 3)
With n == 4, the list is (0 1 2 3 4)
(0 1 2 3 4)
You can also use nconc to create the list, which is like append, only it modifies the structure of the input lists.
(nconc nlist (list (+ 2 2)))
You haven't specified the kind of Lisp, so if you use Emacs Lisp and dash list manipulation library, it has a function -snoc that returns a new list with the element added to the end. The name is reversed "cons".
(-snoc '(1 2) 3) ; (1 2 3)
This function might be useful in some situations, it transparently appends a single element to a list, i.e. it modifies the list but returns the appended element (enclosed in a list):
(defun attach1 (lst x)
(setf (cdr (last lst)) (cons x nil)))
;; (attach1 nlist (+ 2 2)) ; append without wrapping element to be added in a list
(append l (list e)) ; e is the element that you want to add at the tail of a list
Cons-ing at the end of a list can be achieved with this function:
(defun cons-last (lst x)
(let ((y (copy-list lst))) (setf (cdr (last y)) (cons x nil)) y))
;; (cons-last nlist (+ 2 2))
If you are trying to add two lists for example (1 2 3) + (1 2 3) here is the code (recursive)
(defun add-to-all (x y)
(T (appendl (+ (first x) (first y)) (add-to-all (tail x) (tail y)) ))
)
If you are trying to add an item to the end of the second list, for example 3 + (1 2 3)
(defun add-to-all (x y)
(cond ((null? y) nil)
(T (appendl (+ (first x) (first y)) (add-to-all (tail x) (tail y)) ))
)
)
If you want to add an item onto the end of a given list without changing that list, then as previously suggested you can use a function like
(defun annex (lst item)
"Returns a new list with item added onto the end of the given list."
(nconc (copy-list lst) (list item)))
This returns a new extended list, while preserving the input list. However, if you want to modify the input list to include the added item, then you can use a macro like
(define-modify-macro pushend (item)
(lambda (place item)
(nconc place (list item)))
"Push item onto end of a list: (pushend place item).")
Pushend operates like push, but "pushes" the item onto the end of the given list. Also note the argument order is the reverse of push.