Run length encoding of a list in scheme (R5RS) [duplicate] - list

This question already has an answer here:
My code signals the error "application: not a procedure" or "call to non procedure"
(1 answer)
Closed 2 years ago.
(Question Details image -- describes RLE encoding)
The (if ((equal? (car coins) (cadr coins))) piece of code in my rle function is not working, and the function stops working.
(define (element-index lst element)
(let loop ((counter 1) (temp lst))
(if (= element (car temp))
counter
(loop (+ counter 1) (cdr temp)))))
(define (rle coins)
(cond ((null? coins) '()))
(if ((equal? (car coins) (cadr coins)))
(rle (cdr coins))
(append '( cons (element-index (coins) (car coins)) (car coins))
'( cons (rle (cdr coins))))))

I'm not going to answer how to solve the problem of run-length encoding something, but the basic syntax problem.
The summary of this is: in many programming languages, and often in mathematical notation, parentheses serve to control the order of operations, and are often more-or-less optional. So for instance 1 + 2 * 3 probably means 'multiply 2 by 3 then add 1 to the result', while (1 + 2) * 3 means 'add 1 and 2 and then multiply the result by 3'. But 1 + (2 * 3) means the same as 1 + 2 * 3 which means the same as (((1 + (2 * 3)))).
This is not the case in Scheme or Lisp-family languages, ever. In these languages parentheses are part of the syntax of the language and they are never optional: they must either be there, or they must not be there.
So, in particular, a simplified version of the syntax of an expression in Scheme might be: an expression is either
some atomic thing like a variable reference;
a form like (op ...), where op is some operator.
In the second case the parentheses are not optional: they are part of the syntax of the language. And in particular if you consider an expression like
((foo ...))
then this matches the second case, where op is now (foo ...) as a whole (and there are no arguments), and that in turn again matches the second case where op is foo. So this is an expression, whose operator is another expression, and the operator of that expression is foo: it's not an expression wrapped in some optional parentheses, and in particular it is not the case that ((foo ...)) is the same as (foo ...).
So then, the syntax of if is: (if expression consequent alternate). Well, let's look at your if:
(if ((equal? (car coins) (cadr coins)))
...
...)
So the expression here is ((equal? (car coins) (cadr coins))). Well this matches the (op ...) case where op is (equal? (car coins) (cadr coins)), and this in turn matches that case, so it will evaluate this to return either #tor #f. So the expression is the same thing as (#t) or (#f). And #t or #f are Booleans: they're not things you can call as functions.
And that's at least one of the errors in your code. There are others, but this seems to be the most important one, as it's also an error you've made in a comment to another answer.
In summary: parentheses are never optional in Scheme: they are either required or forbidden by the syntax of the language.
Another way of putting this is that, in a 'conventional Algol-style' language, parentheses usually serve two purposes:
they serve as critical and mandatory parts of the syntax, usually for function arguments as f(x, ...), but sometimes also for other syntactic purposes as if (...) ... in C say;
they serve to group expressions to control evaluation order where they are sometimes needed but often optional.
In Lisp-family languages only the former purpose exists.

Related

Why is it possible to use unquote-splicing on a non-list at the end of a quasiquoted list?

The quasiquoted list `(1 ,#2 3) is invalid because 2 is not a list. However, `(1 2 ,#3) is valid and will return a dotted list: (1 2 . 3). I observe this result in Common Lisp and Scheme. Why is it possible to use unquote-splicing for non-lists at the end of a quasiquoted list? Why is the result a dotted list?
The expression `(1 2 ,#3) is not valid in either Scheme or Common Lisp.
Scheme
In R6RS Scheme (and similarly for R5RS), the behavior is not specified for operating on a non-list with unquote-splicing. The R6RS Scheme Standard requires (11.17 Quasiquotation):
If an (unquote-splicing <expression> ...) form appears inside a <qq
template>, then the <expression>s must evaluate to lists....
Common Lisp
The Common Lisp HyperSpec says first that (2.4.6 Backquote):
If a comma is immediately followed by an at-sign, then the form
following the at-sign is evaluated to produce a list of objects.
These objects are then "spliced" into place in the template.
In the sub-expression ,#3, 3 does not evaluate to a list. This seems a pretty strong argument that the expression is not valid. Even if the 3 were magically placed in a list before splicing, this would not result in a dotted list. The HyperSpec goes on to provide a formal summary of backquote syntax. The part of interest is:
`(x1 x2 x3 ... xn . atom) may be interpreted to mean
(append [ x1] [ x2] [ x3] ... [ xn] (quote atom))
where the brackets are used to indicate a transformation of an xj as follows:
-- [form] is interpreted as (list `form), which contains a backquoted form that must then be further interpreted.
-- [,form] is interpreted as (list form).
-- [,#form] is interpreted as form.
So in Common Lisp the original expression, which is equivalent to `(1 2 ,#3 . nil), can be interpreted as:
(append (list `1) (list `2) 3 (quote nil))
But, this is not a valid call to append, which requires proper lists for all arguments except the last one. So, there seems to be no support for the idea that the original expression was valid.
The fact that it worked for the OP in both Scheme and Common Lisp probably comes down to similar definitions for the backquote macro across different implementations. These definitions all seem to expect that the form following ,# will evaluate to a list; when that is not the case, the observed behavior (production of a dotted list) can't be relied upon, according to the standard. That said, I tested Chez Scheme, Guile Scheme, MIT Scheme, SBCL, CCL, and CLisp: all of them exhibited the same behavior reported by OP.
An Interesting Case
I also tested against an implementation of the backquote macro by Guy Steele and published in CLTL2. This case is more interesting. This backquote implementation in CLTL2 is meant for exploring the behavior of backquote expressions and has an optional code simplification phase. Here $ corresponds to a backquote, and %# corresponds to ,#. Without code simplification, the result of expanding the original expression is:
CL-USER> (setf *bq-simplify* nil)
NIL
CL-USER> (try '("$(1 2 %#3)"))
`(1 2 ,#3) = (APPEND (LIST '1) (LIST '2) 3 'NIL)
This corresponds to the expression which was expected above from reading the description in the HyperSpec. But note that this expression will not compile:
CL-USER> (append (list 1) (list 2) 3 nil)
The value
3
is not of type
LIST
[Condition of type TYPE-ERROR]
But, when code simplification is turned on:
CL-USER> (setf *bq-simplify* t)
T
CL-USER> (try '("$(1 2 %#3)"))
`(1 2 ,#3) = (LIST* '1 '2 3)
This "simplified" expression is valid, and evaluates to a dotted list:
CL-USER> (list* 1 2 3)
(1 2 . 3)
My conclusion is that the expression following ,# must be a list per the Common Lisp standard, but some common implementations either do some form of code simplification similar to what is shown in CLTL2 or otherwise expand the backquote form in such a way that it appears that a non-list form can follow ,#. Don't rely on this, as it is difficult to say when it won't work.
Proper lists
Other answers detail this part already, let me rephrase it quickly: lists are either proper lists or improper lists; improper lists are either ciruclar lists or dotted lists.
In particular, a dotted-list is a non-circular list whose last cons cell has a non-list cdr slot.
Some functions are expected to work only when given proper lists, other have no such restrictions, typically because checking for this property is not without costs.
Writing (cons 1 2) creates such a list. Now, if the splicing syntax expands as (cons x y) where y is a non-list, you'll have a dotted-list too.
Slicing
Chapter 2.4.6 Backquote states (emphasis mine):
If a comma is immediately followed by an at-sign, then the form following the at-sign is evaluated to produce a list of objects.
I see no other note indicating that splicing a non-list value might be part of a conforming program, even if it results in practice to an improper list when splicing occurs at the end of the list.
The section also states that:
`((,a b) ,c ,#d)
will be interpreted as if it were
(append (list (append (list a) (list 'b) 'nil)) (list c) d 'nil)
but it could also be legitimately interpreted to mean any of the following:
(append (list (append (list a) (list 'b))) (list c) d)
(append (list (append (list a) '(b))) (list c) d)
(list* (cons a '(b)) c d)
(list* (cons a (list 'b)) c d)
(append (list (cons a '(b))) (list c) d)
(list* (cons a '(b)) c (copy-list d))
Expanding as calls to standard functions like list* or append make that corner case naturally produce improper lists, but notice that the first and last example do not allow splicing for the last element. For instance:
(list* (cons a '(b)) c (copy-list d))
The above form complains when d is not a list, because COPY-LIST only works with lists (either proper or dotted, but here it would be given a non-list value, e.g. a number).
It is thus my understanding that this expression:
`(1 2 ,#3)
is in fact invalid in Common Lisp and happens to works only by accident. Writing it could expose you to portability problems.
Conclusion
Why is it possible to use unquote-splicing for non-lists at the end of a quasiquoted list?
It happens by chance in your implementation because backquotes, unquotes and splicing are rewritten/expanded as list building functions that may produce dotted lists in that corner case, without signaling an error.
Why is the result a dotted list?
Because the code probably is interpreted as a call to append where the last item is a non-list value, which results in a dotted list. It does not work when splicing in the middle of a form, because append expects proper lists for all but the last arguments.
Bonus
Today I learned about ,. which is like ,# except is may use nconc instead of append
To construct a list of 3 variables with quasiquoting, one could write
`(,x ,y ,z)
This can be desugared to
(cons x (cons y (cons z nil)))
What if z is a list, and we want to splice its contents into the resulting list? Then instead of creating a new cons for it, we simply put it at the tail. When we write
`(,x ,y ,#z)
this desugars to
(cons x (cons y z))
If z happens to not actually be a list, then the result is a legal value, although not a proper list. For example, (1 2 . 3), as you observed. You will see the same result if you write the desugared form explicitly, as (cons 1 (cons 2 3)). If this also troubles you, you may want to investigate the concept of improper lists in general, or dotted pair notation.
'(1 2 3) is actually (cons 1 (cons 2 (cons 3 nil))).
So, the last element in '(1 2 3) is not a 'non-list', but a (cons 3 nil) i.e. (list 3), and thus can be spliced.

scheme getting the last element in a list

Im very new to scheme and the ideas of car, cdr, etc. I have this function to return the last element of a list, but right now it just returns an empty list.
(define (last mylist)
(if (list? mylist)
(if (null? mylist)
(if (null? (cdr mylist))
'()
(last (cdr mylist))
)
)
)
)
The book How To Design Programs helps you answer this problem by giving you a specific and detailed design recipe. This particular problem is covered in section 9.2, "Non-empty Lists". Broadly, here are the steps you need to follow:
formulate a data definition for non-empty lists (or take it from the book)
write the purpose statement, signature, and header for your function
WRITE TEST CASES (your test cases are going to help a lot here. (keep in mind that you don't need to test inputs that aren't allowed by your data definition)
add the template associated with your data definition (also appears in the book)
fill in the blank places in the template to complete your definition
debug.
By your indentation alone, it's very evident that you're coming to Scheme from another programming language
But you're also using if incorrectly – in Scheme, you cannot have a single-branch if statement. Well, there's no statements in Scheme at all, only expressions, and if expressions will always take 3 operands (arguments)
the predicate (condition)
the consequent (what happens if the predicate is true)
the alternative (what happens when the predicate is false)
Your program is close tho. Just a little adjustment and you're right where you need to be – take note of how the indentation makes it easy to see if's 3 operands.
(define (last mylist)
(if (null? mylist)
#f
(if (null? (cdr mylist))
(car mylist)
(last (cdr mylist)))))
Lastly, Scheme offers cond that helps prevent unnecessary code nesting for sequences of conditions
(define (last mylist)
(cond ((null? mylist)
#f)
((null? (cdr mylist))
(car mylist))
(else
(last (cdr mylist)))))
(last '())
;; #f
(last '(1))
;; 1
(last '(1 2))
;; 2
(last '(1 2 3))
;; 3
Beyond the scope of this answer is the return value #f for (last '()) – I would argue that calling last on an empty list should have the same effect of calling car on an empty list. But I'll leave it up to you.
If (null? mylist) does not hold, what is it? A non-empty list.
Non-empty lists may have one, or more, elements.
How many elements have such lists that their last element is their first?
What can be said about such lists' cdr? You should use this to stop your recursion earlier. Right now it continues until the list is empty, but you need to stop earlier than that.
(define (last mylist)
(if (list? mylist)
(if (null? mylist)
'()
;; {1}
(last (cdr mylist))
;;
)))
at {1} you call (last (cdr mylist)) unconditionally. But what if you've reached the end of your list? What if only one element is left? You'll need to return it as the result, in such case. So, replace the unconditional code with an if expression to accomplish this.
When you asked the question (null? (cdr mylist)), you should have returned (car mylist) if that's true instead of '(). Since at that point it means that mylist is a single-atom list.
(define (last mylist)
(cond ((null? mylist) '())
((null? (cdr mylist)) (car mylist))
(else (last (cdr mylist)))))
You could use cond instead of if to avoid nested conditions, since cond handle many arms while if is often used for when you have only two options for a condition.
This book the Little Schemer did best at helping me visualize what's going on in a Scheme program.
I think this comes closest to your initial code:
(define (last mylist)
(if (list? mylist)
(if (null? mylist)
'() ; input list is empty
(if (null? (cdr mylist))
(car mylist) ; list only has one remaining element so this is it
(last (cdr mylist)))) ; otherwise, recurse
#f)) ; input is not a list
When using if, be sure to always fill out both the true and the false branches.

Remove duplicates and sort a list

I am trying to write a procedure that takes a list that may or may not include duplicates, and then return that list without duplicates, and in sorted order. What I came up with so far is:
(define (remove-duplicated list)
(if (null? list)
'()
(if (= (car list) (cadr list))
(cdr list)
(cons (car list) (remove-duplicates (cdr list))))))
I'm not quite sure what the problem is, besides sorting the list. For example, if I input
(remove-duplicates '(3 3 4 5 6 6 7))
returns
(3 4 5 6 6 7)
a fairly simple procedure that will take in a list that may or may not
include duplicats, and then return that list without any duplicates
included, and in sorted order.
There are at least two ways that you could do this:
sort the list once the duplicates are removed; or
remove the duplicates after the list has been sorted.
Óscar López pointed out that
[Your] implementation fails because you're only testing for two
consecutive values, you have to search the current element in the rest
of the list, use member for that.
This will be an issue if you remove the duplicates before sorting, since a given element in the list could have duplicates anywhere else in the list. However, if you sort the list first, then you would be guaranteed that any duplicate elements do immediately follow the original, so you wouldn't need to check the whole list. Removing duplicates is easier if the list is sorted, but sorting a list isn't really any easier after duplicate elements are removed, so it really does make sense to sort the list first and then remove duplicates. (I suppose you could be even more efficient, and write your own sort-and-remove-duplicates procedure, but almost certainly not really necessary.)
Your code, if you're assuming that list is already sorted, is almost correct. There are two adjustments necessary:
In the base case, you're only checking whether (null? list). However, for a non-null list, you then compare (car list) and (cadr list), but if list only has one element, then (cadr list) is an error. Fortunately, lists with only one element have no duplicates, so your base case can be (or (null? list) (null? (cdr list))).
The then part of the second if needs to be (remove-duplicated (cdr list)), not (cdr list), since list can still have more duplicates farther down (e.g., (x x x ...) or (x x y y ...)).
This is your code with those modifications and some comments:
(define (remove-duplicated list)
;; remove duplicates from a *sorted* list. Because the
;; list is sorted, any duplicates of an element will
;; immediately follow the first occurrence of the element.
;;---------------------------------------------------------
;; If the list has the form () or (x)
(if (or (null? list)
(null? (cdr list)))
;; then it has no duplicates, so return it
list
;; otherwise, if the list looks like (x x ...)
(if (= (car list) (cadr list))
;; then you can discard the first element, but you
;; still need to remove duplicates from the rest of
;; the list, since there can be more duplicates later
(remove-duplicated (cdr list))
;; otherwise, you need the first element of the list
;; and can simply remove-duplicated from the rest.
(cons (car list) (remove-duplicated (cdr list))))))
This works as expected:
(remove-duplicated '(1 1 2 3 3 4 5 6))
;=> '(1 2 3 4 5 6)
The fact that the input list might be sorted slipped my mind. What I'm about to describe will work for removing duplicate elements from any list, sorted or not. For the general case of removing duplicates in a list, you have to search the current element in the rest of the list, using member for that.
Also, you have to advance the recursion in both cases, and be aware that in the last line you're calling remove-duplicates (which is a built-in procedure in some interpreters, so maybe you don't have to implement it from scratch!), but you named the procedure remove-duplicated. As a side note, it's a bad idea to name a parameter list, that'll clash with a built-in function - I took the liberty of renaming it. This will fix the problems, and it's a more general solution:
; if the input list is not sorted, use this
(define (remove-duplicated lst)
(if (null? lst)
'()
(if (member (car lst) (cdr lst)) ; changes here
(remove-duplicated (cdr lst)) ; and here
(cons (car lst)
(remove-duplicated (cdr lst))))))
Now, if the input list is sorted to begin with, this is how to fix your code. Most of my comments apply, except that you don't have to use member and the base case is a little different:
; if the input list is sorted, use this
(define (remove-duplicated lst)
(if (or (null? lst) (null? (cdr lst))) ; changes here
lst
(if (= (car lst) (cadr lst))
(remove-duplicated (cdr lst)) ; and here
(cons (car lst)
(remove-duplicated (cdr lst))))))
Either way, the procedure will work as expected as long as you use the right one for the input (the first implementation is for sorted or unsorted input lists, the second one works only for sorted lists):
(remove-duplicated '(3 3 4 5 6 6 7)) ; sorted input, both implementations work
=> '(3 4 5 6 7)
Finally, if you need to make sure that the output list will always be sorted, but have no guarantees that the input list was sorted, then use my first implementation of remove-duplicated and sort it afterwards, check your interpreter to find out which sorting procedures are available - the following will work in Racket:
(sort (remove-duplicated '(3 6 3 7 4 5 6)) <) ; using my first remove-duplicated
=> '(3 4 5 6 7)
… Or sort the list first and then use my second implementation of remove-duplicated. You have so many options to solve this problem!
(remove-duplicated (sort '(3 6 3 7 4 5 6) <)) ; using my second remove-duplicated
=> '(3 4 5 6 7)

Lisp - Checking if a symbol is in a list of lists

I am trying to create a function which has a symbol/token and a list passed in
the function will then check to see if the list contains the symbol/token. if so return its corresponding key pair and if not return nul
I made a defparameter which was:
(defparameter *pairs*
'((apple green)
(banana yellow)
(grape purple)))
i then made a function to do the task:
(defun list-pairs (word list)
(if (eq word list)
(rest(list)))
nil))
the function when executed as such : (list-pairs '(banana) *pairs*) i keep getting nul
what i want to be returned is yellow i.e. the key pair
can someone please help me as to explaining whats wrong. I am very new to LISP
(second (assoc 'banana *pairs*))
gives
YELLOW
Edit: See Joshua Taylor's comment below for documentation about assoc and the concept of association lists (or short: alists) that it works with (very briefly: alists are a key-value data structure formed by lists of cons cells in which the car of each cons cell is the key and the cdr is the value).
About what's wrong with your own code:
In the condition of your if: (eq word list), you are testing whether your argument word is the same as your argument list. But you actually want to look for word within list, so that cannot be the right condition.
Also, even if the condition were true, what you're then evaluating is (rest(list)). That is the rest of a new empty list, created by calling the function list, not the rest of your argument list.
And finally, you're closing the if expression after that (rest(list)) with the third closing parenthesis there. Because of that, the final nil would be the return value of your function even if everything else would be correct. You need to move the nil into the parentheses of the if expression to make it the else-consequent, and the value of the if expression the return value of the function.
What you are looking for is
(defun list-pairs (word list)
(if list
(if (eq (caar list) word)
(cadar list)
(list-pairs word (cdr list))))))
or, using let as a small optimisation:
(defun list-pairs (word list)
(if list
(let ((c (car list)))
(if (eq (car c) word)
(cadr c)
(list-pairs word (cdr list))))))
which works well with a Common Lisp implementation that does tail-call optimisation; you should use it like
(list-pairs 'banana *pairs*)
but in Common Lisp the loop macro is generally preferred:
(defun list-pairs (word list)
(loop for c in list
when (eq (car c) word)
return (cadr c)))
As another alternative:
(defun list-pairs (word list)
(dolist (p list)
(if (eq word (first p))
(return (second p)))))
(defparameter *pairs*
'((apple green)
(banana yellow)
(grape purple)))
(list-pairs 'banana *pairs*)
YELLOW
Your task leaves some questions open to me.
1.) Your function should get a symbol. But why do you call it like this: (list-pairs '(banana) *pairs*)? Wouldn't be (list-pairs 'banana *pairs*) sufficient?
2.) Do you only want to get matches for the first element of your pairs? I.e. Do you want the same result for the symbol banana and yellow?
If you only want to search for the first element, Rörd already mentioned assoc, which would be perfect.
If you want to check both elements of the pair, you can give remove-if-not a try.
(defun list-pairs (word list)
(remove-if-not
#'(lambda (sublist) (member word sublist))
list))

Just trying to recursively print a list, nothing prints though

I would like to go through a list (which may have nested lists) and have it evaluate to one flattened list with all of the elements. I can't even get a recursive function to evaluate to anything other than nil
(defun pl(lst)
(if (atom lst)
lst
(progn
(pl (car lst))
(pl (cdr lst)))))
I'll then call with something like (pl '(1 (2 3) (4 5))), but it always evaluates to nil.
I changed
(if (atom lst) lst
to
(if (atom lst) (print lst)
and this doesn't even print any of the items of the list.
what concept I am missing here?
A function will normally only return one value, which is value of its body. If you look closely at pl you see that it is an if form, so pl either returns the value of lst or the value of progn.
The first thing I have to point out here is that the return value of a (progn ...) form is the value of its last expression, which in this case is the recursive call (pl (cdr lst)). As you do not do anything with the return value of (pl (car lst)) this call has no effect whatsoever. The value of the recursive call will at some point fall through the atom test. The second thing to point out here is that (atom nil) is also true. Remember that the last element of a list is nil, so when you give pl a list it will always return nil as you have observed.
If your print version shows nothing, it is probably because the print output is shown somewhere else, in another buffer for example.
As for the solution: you either want a pure recursive solution by using append instead of progn, because that's what in your homework assignment. In regular lisp you just use one of the iteration constructs.
My advice is to check any textbook on lisp or scheme to grasp the fundamentals of recursion and tail-recursion.
You might consider looking at an introductory text like "The Little Schemer". One of the first things it does is shows you how to take a consistent approach to problems just like this. The resulting function might look like:
(define (pl lst)
(cond ((null? lst) '())
((not (pair? lst)) (list lst))
(else (append (pl (car lst))
(pl (cdr lst))))))
Sure, this is Scheme, but the approach is the same for Lisp:
Check for the special case where the argument is nil
Check for the special case where the argument is an atom
Recursively apply the function to the car and cdr of the argument, appending the results
The same function in Lisp would look like:
(defun pl (lst)
(cond ((null lst) '())
((atom lst) (list lst))
(t (append (pl (car lst))
(pl (cdr lst))))))
Arguments can be made that this is not the most efficient code, but that isn't the point. This type of pattern occurs over and over again. It's a good idiom to learn.