Why aren't cyclic lists considered lists in Scheme? - list

I haven't found any questions regarding this for the Scheme programming language, so I hope this isn't a duplicate.
While doing some dabbling in the interpreter I encountered a peculiar occurrence:
(define li (list 'a 'b 'c 'd 'e))
(list? li)
;; -> #t
(set-cdr! (cddddr li) li) ;; list is now circular
(list? li)
;; -> #f
Apparently, upon changing the list object to now be cyclic, list? will return #f.
How come Scheme doesn't consider a cyclic list to be a list? I guess it has something to do with the formal definition of list, but how does Scheme formulate such definition? Also, how is list? even implemented in terms of possessing the property of detecting a cyclic list?

I think that a natural definition of a list is that a list is either:
the empty list, ();
or a pair whose car is any object and whose cdr is a list.
Note that a circular list does not meet this criteria, and neither does something like (x . y) or (x y . z).
I believe that this is the definition of 'list' used by RnRS for at least some values of n (in particular it's the definition used by R5RS). R5RS is clear, again, that list? must return false for a circular list (so in particular it must have an occurs check or something like it).
Other Lisps have historically been much more lax about this: Common Lisp for instance defines it's listp simply checks if an object is either () or a cons, and defines lists as being elements of that type. What Scheme calls 'lists' Common Lisp calls 'proper lists'.
Here is a version of list? which uses an a tortoise-and-hare algorithm to check for circularity (this may not be correct and I think is overcomplex even if it is, but it's late):
(define (lyst? l)
(cond
[(null? l)
#t]
[(not (cons? l))
#f]
[else
(let lyst-loop? ([tortoise l]
[hare (cdr l)])
(cond [(eq? hare tortoise)
#f]
[(null? hare)
#t]
[(cons? hare)
(cond [(null? (cdr hare))
#t]
[(not (cons? (cdr hare)))
#f]
[else
(lyst-loop? (cdr tortoise)
(cdr (cdr hare)))])]
[else
#f]))]))

Related

Scheme - list passed into function returning empty

I am trying to define a helper function that takes an integer and a list as parameters and produces cartesian product of the integer and the list.
I believe I have the logic figured out. But when I test my code and pass a list into the function, the function returns an empty list.
(define (helper element set)
(cond
((null? set) '())
(cons '(element (car set)) (helper element (cdr set)))
)
)
For example, when I run (helper 5 '(6 8 9)) it returns an empty list.
I can't figure out why, but I think it has something to do with passing an integer with a list as parameters but I can't find anything to confirm this.
You have the wrong syntax for cond. The format is
(cond (test1 then1)
(test2 then2)
...)
There is no special allowance that the last case doesn't need a test. So when you write
(cond
((null? set) '())
(cons '(element (car set))
(helper element (cdr set))))
your test is the symbol cons, and your then-expression is "evaluate '(element (car set)), throwing the result away, and then evaluate and return (helper element (cdr set))" (there is an implicit begin around the expressions in the then part of a cond). Thus, helper always just recurses down to an empty set eventually, and then returns it, making no changes to it.
What you meant to do instead was use something that's always true as your last test, and then use the cons form as the body. Traditionally else is used for this, although #t is also fine:
(define (helper element set)
(cond
((null? set) '())
(else (cons '(element (car set))
(helper element (cdr set))))))
You will then discover another problem, which is that you meant to construct a list containing the values referred to by element and (car set), not to quote that list. What is the difference between quote and list? will help you understand what's doing on there.
try this:
(define (helper element set)
(map (lambda(x) (cons element x)) set))

In Racket how do i find the length of a list using struct instead of just using only higher-order functions or recursion

I'm pretty bad at understanding data structures in Racket right now so I'm currently working on a question where all I have to do is find the length of the list.
I understand there are many ways to find the length of a list using recursion and foldr and map but I'm trying to find the length of a list a specific way right now.
Here are the details of the question;
For this question, use the following data definition:
(define-struct ls (first rest))
;; a Ls is either
;; '(), or
;; (make-ls first rest) where first is an Int and rest is a Ls.
Keep in mind that since the structure is named ls, and its fields are named first and rest,you will access these fields using ls-first and ls-rest.
Here is the question
Length. Write a function (ls-length L) that consumes a Ls and returns the number of values in it.
For example, (check-expect (ls-length (make-ls 5 (make-ls 7 (make-ls 11 '())))) 3)
Here's a common way to find the length
(define (length lst)
(cond
[(empty? lst) 0]
[(cons? lst) (+ 1 (length (rest lst)))]))
I however want the question solved using
(define-struct ls (first rest))
This is what I have so far but I know that this code seems very wrong, I feel my base case should be correct though.
(define (ls-length L)
(cond
[(empty? L) 0]
[(cons? (ls-first (first L))) (+ 1 (length (rest (ls-rest))))]))
You have to remember that you can't use cons?, rest and first on the new data structure, only empty?, ls-first and ls-rest are allowed. The conditions are quite simple: the list is either empty or not empty, we don't really need cons?. Also, be careful when calling the recursion, the procedure is called ls-length, not length:
(define (ls-length lst)
(cond
[(empty? lst) 0]
[else (+ 1 (ls-length (ls-rest lst)))]))
Compare the above with the well-known length implementation:
(define (length lst)
(cond
[(empty? lst) 0]
[else (+ 1 (length (rest lst)))]))
You see what happened? we only had to replace length with ls-length, and rest with ls-rest. So simple!

Scheme function to take a list and an atom as parameters and returns index of the first location where atom occurs

I'm very new to Scheme and am working on a problem defined as follows:
Write a scheme function find-loc which takes two parameters, a list lst and an atom atm, and returns the index of the first location where atm occurs in the list.
The location index is 1-relative. If atm does not occur in the list, the function returns n + 1, where n is the length of the list.
what I've got so far is:
(define (find-loc list atm)
(if (not(list? list))
0
(cond
((null? list)
1)
((eq? (car list)atm)
1))
(else (+ (find-loc (cdr list atm) 1) )))
I feel that I'm close but am a bit stuck. My main questions are as follows:
how do I define what the atom is?
why am I getting the following error? "define: expected only one expression for the function body, but found 1 extra part"
An atom is defined by this predicate:
(define (atom? x)
(and (not (null? x))
(not (pair? x))))
The error you're receiving is because the syntax of the if expression is incorrect - it must have two parts after the condition (consequent and alternative), and you wrote three. A few comments:
It's better to use a cond when testing for multiple conditions
Don't name a variable as list, it clashes with a built-in procedure of the same name
Better use equal? for testing equality, it's more general
We should use our new and shiny atom? predicate, as per the requirements - even though the null? check is redundant at this point
This is what I mean:
(define (find-loc lst atm)
(cond ((not (list? lst)) 0)
((null? lst) 1)
((and (atom? (car lst)) (equal? (car lst) atm)) 1)
(else (+ 1 (find-loc (cdr lst) atm)))))

Adding an element to List in Scheme

Below is my code which takes a car element of a list(carVal) and an list(initialized to empty) as parameters. I want to append the element to the list but the same is not working.
(define populateValues
(lambda (carVal currVal)
(append currVal(list carVal ))
(display currVal)))
The display shows empty list all the time () . Can anyone help me understand why?
Well, there is append! as a primitive, which solves most of your problems, as noted already, Scheme tends to frown on mutation, it is possible, but typically avoided, so all procedures that mutate have a ! (called a bang) at their end.
Also, set! does not mutate data, it changes an environment, it makes a variable point to another thing, the original data is left unchanged.
Mutating data in Scheme is quite cumbersome, but, to give you my own implementation of append! to see how it is done:
(define (append! lst . lsts)
(if (not (null? lsts))
(if (null? (cdr lst))
(begin
(set-cdr! lst (car lsts))
(apply append! (car lsts) (cdr lsts)))
(apply append! (cdr lst) lsts))))
Note the use of set-cdr!, which is a true mutator, it only works on pairs, it mutates data in memory, unlike `set!'. If a pair is passed to a function and mutated with set-cdr! or set-car!, it is mutated every-where in the program.
This obeys the SRFI append! spec which says that it should be variadic and that it should return an undefined value, for instance.
(define l1 (list 1 2 3 4))
(define l2 (list 2 3 4))
(define l3 (list 3 1))
(append! l1 l2 l3)
l1
l2
l3
Which displays:
(1 2 3 4 2 3 4 3 1)
(2 3 4 3 1)
(3 1)
As visible, append! can take an infinite number of arguments and it mutates them all but the last.
Scheme might not be the ideal language for you though. The use of append! as said before is nonstandard, instead, append is preferred, which does not mutate and is called for its return value. Which I implement as such:
(define (append . lsts)
(cond
((null? lsts) '())
((null? (car lsts)) (apply append (cdr lsts)))
(else (cons (caar lsts) (apply append (cdar lsts) (cdr lsts))))))
> (append (list 1 2 3) (list 4 5 6) (list 'granny 'porn))
(1 2 3 4 5 6 granny porn)
Which shows a more familiar Scheme style in the absence of mutation, heavy use of recursion
and no use of sequencing.
Edit: If you just want to add some elements to a list and not per se join two though:
(define (extend l . xs)
(if (null? l)
xs
(cons (car l) (apply extend (cdr l) xs))))
(define (extend! l . xs)
(if (null? (cdr l))
(set-cdr! l xs)
(apply extend! (cdr l) xs)))
(extend '(0 1 2 3) 4 5 6)
(define list1 '(0 1 2 3))
(extend! list1 4 5 6)
list1
Which does what you expect
append creates a new list, it does not modify an existing one.
This is because in general, Scheme (and Racket in this case) is a language that prefers functional style.
You could get somewhat closer with a set! -- but even that will disappoint you since it will modify only the local binding.
Note that in Racket in particular, lists are immutable, so there's nothing that can change a list.
Furthermore, even if you could modify a list this way, it's a very inefficient way to accumulate long lists, since you have to repeatedly scan the whole list.
Finally, if you have issues at this level, then I strongly recommend going over HtDP
(append foo bar) returns the concatenation of foo and bar. It doesn't change either foo or bar.
You have to update the value of currVal with set!. Your example should have
(set! currVal (append currVal (list carVal))
(display currVal)
You really need to think about what exact functionality you are looking for
If you want to mutate a referenced list in place, then you have to do the equivalent of append! (as noted in the other answers). But that is dangerous, BECAUSE you may have other code that is counting on the list being immutable, and if you are going to do that, your procedure needs to have a ! in the end to flag that danger.
A cheap approximation to what you want to do, in a more functional style, is:
(define (populateValues carVal currVal)
(let ((ll (append currVal (list carVal))))
(display ll)
ll))
Note that it makes a new list, does the append, displays the result, and RETURNS the new list as a value. This is a useful debugging technique if you don't have access to the intermediate value: bind to a varible, display or log it, and then return it.

Scheme Compare item or list if it's inside the test list (can be nested)

My Goal is to make the function part? return true if a list or an item is inside the nested list.
But so far I can only get it working with signal item inside a first order list. (not nested list yet)
(define part?
(lambda (item l)
(and (not (null? l))
(or (= item (car l))
(part? item (cdr l))))))
my goal is to have
part? of (A (B)), (((B) A (B)) C) is #f and
part? of (A B), (C (A B) (C)) is #t
Where I should improve on this? How can I make the list to compare with the nested list?
DISCLAIMER: I haven't written scheme regularly in 20 years.
I think you want to think about this problem in terms of the whole lispy/schemey approach which is to establish your conditions.
Given an input, item, you want to find if a list contains that item.
A list may contain an item if the list is not null.
A list contains an item if the car of the list matches the item or if the car of the list contains the item
A list contains an item if the cdr of the list contains the item.
A final question to consider, what is the result of (part? '(a b) '(a b))?
I would write the code like this
(define part? (lambda (item l)
(cond ((null? l) f)
((or (same? item (car l)) (part? item (car l))))
(t (part? item (cdr l)))
)
))
(define same? (lambda (a b) (eq? a b)))
I used the cond structure because it fits well with problems of this sort - it just feels right to break the problem out - notice the null check. I wrote same? as a helper function in case you want to write it yourself. You could just as easily to it this way:
(define same? (lambda (a b)
(cond ((and (atom? a) (atom? b)) (eq? a b))
((and (list? a) (list? b)) (and (same? (car a) (car b)) (same? (cdr a) (cdr b))))
(f f)
)
))
which basically says that two items are the same if they are both atoms and they are eq or they are both lists and the cars are the same and the cdrs are the same, otherwise false.
You can just as easily rewrite same? as this:
(define same? (lambda (a b) (equal? a b)))
The point of doing that is that there is a bottleneck in the code - how to determine if two items are the same. If you break that bottleneck out into its own function, you can replace it with different mechanisms. I know you're not here yet, but you will be at one point: you will also be able to rewrite the code so that the predicate is passed in. Something like this (and more up-to-date scheme programmers, feel free to correct me):
(define part-pred? (lambda (same-pred item l)
(cond ((null? l) f)
((or (same-pred item (car l)) (part? item (car l))))
(t (part? item (cdr l)))
)
))
(define part-eq? (lambda (item l) (part-pred? 'eq? item l)))
(define part-same? (lambda (item l) (part-pred? 'same? item l)))
(define part-equal? (lambda (item l) (part-equal? 'equal? item l)))
This has now abstracted the notion of part to be a function that applies the part structural rules and an equality predicate which is supplied by you. That makes it really easy to change the rules. This will make more sense when you hit mapcar.
The problem with the = function used here is, that it is only defined for numbers. To test arbitrary data for equality, there are the predicates eq?, eqv?, and equal?. These are listed here from most discriminating (eq?, basically something like a pointer comparison) to least discriminating (equal? will consider type and structure). The eqv? predicate is somewhere in between (type-aware for numbers, otherwise like eq? for anything else).
To compare lists, you will usually use equal?.
Edit Details on these predicate can be found in the R6RS.
Your solution is missing the idea, since you're dealing with nested lists you need to check if each item in each list is a list itself, if it is then check if the given list is part of the other or part of the rest of the list if not then you need to check the first items are equal and if the rest of the given list is part of the other.
(define part? item l
(cond (and (list? (car item)) (not (list? (car l))) ...)
(and (not (list? (car item))) (list? (car l)) ...)
(and (not (list? (car item))) (not (list? (car l))) ...)
(and (list? (car item)) (list? (car l))) ...)