I am trying to make the function remove-member, where I have a list of strings and I give one of the members of the string (i.e. "A") to the function, and it removes that member and returns the rest of the list without that member. At the moment I have created tests and started my function, but I am lost beyond that. I know recursion functions include the first member of the list and the rest of it, but how would I remove the first member of a string?
(define str (list->string (list 'A 'B 'C)))
(check-expect (remove-occurrences "A") (list 'B 'C))
(check-expect (remvove-occurrences '()) (list 'A 'B 'C))
(define (remove-occurrences r)
(cond
[(empty? r) str]
[(??? r)]))
To remove a single element from a list:
Is the list empty? If it is, we're done and the result is the empty list.
OK, it's not empty. Is the first element of the list the same as the element you want to remove? If it is then the result is the rest of the list.
OK, it's not empty, and the first element didn't match. So the answer is a list consisting of a cons of the first element and the result of removing the element from the rest of the list. Which you now know how to do.
Alternatively, to remove all occurrences of an element from a list:
Is the list empty? If it is, we're done and the result is the empty list.
OK, it's not empty. Is the first element of the list the same as the element you want to remove? If it is then the result is the the result of removing all occurrences of the element from rest of the list, which you know how do to now.
OK, it's not empty, and the first element didn't match. So the answer is a list consisting of a cons of the first element and the result of removing the element from the rest of the list. Which you now know how to do.
How these functions differ:
> (remove-one '(a b b c) 'b)
'(a b c)
> (remove-all '(a b b c) 'b)
'(a c)
Let's follow the data type.
This way we get the mundane tasks taken care of automatically for us, and get to focus our creative mental abilities on more interesting, less common aspects of our problem:
(define (list-p ad)
(cond
((null? ad) ; follow
#t)
((pair? ad)
(let ((a (car ad)) ; the
(d (cdr ad))) ; type!
(list-p d)))
(else #f)))
We can see this predicate as a constructor of Boolean values. Creating a list following the same example aka skeleton code is also easy:
(define (list-l ad)
(cond
((null? ad) ; return proper
(list)) ; type here, and
((pair? ad)
(let ((a (car ad))
(d (cdr ad)))
(list-l d))) ; here
(else #f)))
We've just followed the type's skeleton code, mended it in the few appropriate places, and got ourselves a working code which creates values of the proper type, all by itself!
But does it create any interesting value, fully using the supplied argument? Evidently, not. For that we must mend the recursive call:
(define (list-copy ad)
(cond
((null? ad)
(list))
((pair? ad)
(let ((a (car ad))
(d (cdr ad)))
(cons ... ; here
(list-copy d))
))
(else #f)))
Now you get to tweak this further, consing the first element of a pair conditionally, as required by your problem.
(note: null? could be called empty? in your dialect).
Related
Tasked with adding a to end of (b c) to make (b c a)
So far when I try
(print (cons 'a '(b c)))
I get (a b c)
but when I do
(print (cons '(b c) 'a))
I get ((b c) . a)
All the other similar questions on Stack seem to be more complicated than this problem so I was wondering if there was an easy fix.
A list is a chain of pairs. The elements are the cars of each pair, the cdr is a reference to the next pair in the chain, or an empty list for the last pair in the chain.
When you use (cons 'a '(b c)) you create a new pair in front of the existing list (b c), so the result is still a list.
But when you use (cons '(b c) 'a), you're creating a pair whose cdr is the symbol a, not a list. And the last pair in the list (b c) still has its cdr pointing to the empty list.
You need to copy the first list, and when you get to the end, you have to make the cdr point to a list containing a. You can do this with a recursive procedure.
(define (list-append old-list new-el)
(if (null? old-list)
(list new-el)
(cons (car old-list)
(list-append (cdr old-list) new-el))))
(list-append '(b c) 'a)
The logic is:
If we try to append to an empty list, just return a list containing the new element
Otherwise, append the new element to the tail of the original list with the recursive call, and then put the first element in front of that (using the (cons new-element old-list) method that you showed in your first example).
I am writing a function that will take a list from a user and will flatten this list into one simplified list. The function seems to only return the first item on the list and not the rest? Any suggestions on why it is doing this?
Example:
> (flatten '(a () b (c d))
(a b c d)
This is what I have so far
(defun flatten (list)
(cond
((null list)t)
(list (first list) (rest list))
(t(append (flatten (first list))
(flatten (rest list)))
(t(cons (first list (flatten (rest list))))))))
The output it is giving
> (flatten '(a () b (c d)))
(NIL B (C D))
You are editing the original question with updated code, which makes it a moving target. Currently, your code is the following one, after I ask Emacs to indent it with M-q (lisp-mode):
(defun flatten (list)
(cond
((null list)t)
(list (first list) (rest list))
(t (append (flatten (first list))
(flatten (rest list)))
(t (cons (first list (flatten (rest list))))))))
;; ^^^ Something is not good, why is the clause indented?
Parentheses structure the code for the computer, whereas indentation is a way to print this structure for human readers. This redundancy allows you to detect problems in source code when one does not match the other. Here, the (t cons) is not a cond clause, it is nested inside the previous clause.
Second, as said in comments, cond will go to the first clause for which the test succeeds. If you wrote (cond (t X) ...), nothing in the ... part would change the meaning of the code, which always returns X. In your code, you test as follows:
(null list) tests whether list is eq to nil.
list does not test whether list is a list. There is a predicate named listp to detect that. When you put list alone like this, you are asking whether list is a generalized true value, which is necessarily true when you previously ruled out nil (the previous clause).
The default clause (t ...) has no way to be used, because the previous test cannot fail.
Here is a skeleton:
(defun flatten (form)
(cond
((null list) ...)
((consp list) ...)
(t ...)))
Instead of consp you could write listp, but note that by definition a list is either nil or a cons cell, so consp is a little more explicit and does not overlap with a test for nil. Note also that I always test against the type of form, which is a pattern that is often found. That's why you might prefer to use typecase.
I was wondering what (cons? list-name) does. Does it just check that list-name is not a non-empty list? Is it just like the opposite of (empty? list-name)? If so, then is it not better to just say (empty? list-name) and then say else instead of cons?? For example:
(define (f list-name)
(cond
[(empty? list-name) empty]
[(cons? list-name) "do something]))
jozefg's answer is right in pointing out that (cons? x) is not the same as (not (empty? x)), in general, because there are things (e.g., numbers) that are neither cons cells nor the empty list.
However, your variable was list-name, so you may have some reason to expect that its value is, in fact a list. A list, in Scheme, is either:
the empty list; or
a cons cell whose car is the first element of a list and whose cdr is the rest of the list.
Because of this, if you're writing a function that requires a list be passed in, then it does make sense to simply check for the trivial case (the empty list) with empty?, and to assume, since you've required a list, that anything that doesn't match that case is a cons cell on which you can call cdr and cdr. This is because while
(cons? x) == (not (empty? x))
is not true of values in general, it is true for lists. That is, if you already know that lst is a list, then
(cons? lst) == (not (empty? lst))
is true. There are a number of functions that do the same thing when we're talking about lists and cons cells. E.g., empty? and null? do the same thing, but they signal a slightly different intent on the part of the programmer. Similarly, car and cdr do the same thing as first and rest, but car and cdr signal that you might be treating something as a pair of two things, whereas first and rest clearly signal the intent that you're working with a list.
Your code, since it seems to expect a list, should probably be the following, since, for a list, if it's not the empty list, it must be a cons.
(define (f lst)
(cond
[(empty? lst) empty]
[else "do something]))
More generally, the code you write should depend on what kind of input you expect. E.g., in the first case, it's fine to check for empty, and assume a cons otherwise, because you're expecting a list. In the second case, you have to check for all the different kinds of things you might see.
(define (frob-list lst)
(cond
[(empty? lst) empty] ; arg is ()
[else ...])) ; arg is (x . y)
(define (frob-object obj)
(cond
[(null? obj) ...] ; arg is ()
[(cons? obj) ...] ; arg is (x . y)
[(number? obj) ...] ; arg is r
... ; arg is ...
[else ...])) ; else ...
cons? checks whether the value is a cons cell, e.g., something that's (cons foo bar) for some foo and bar.
> (cons? 1)
#f
> (cons? '())
#f
> (cons? (list 1 2 3))
#t
> (cons? (cons 1 2))
#t
If (cons? a) is true, then it is safe to use car and cdr on a.
This isn't the opposite of empty? since empty? is true if and only if the argument is the empty list, so (empty? 1) == (cons? 1) == #f.
Sidenote: Please don't put PLEASE HELP!! or similar in your question titles, everyone here is happy to help, but it's a bit obnoxious to read. Just something to keep in mind in the future. Welcome to SO.
I want to get the second value of '(a b c) and I don't want to use cadr.
I can get the right answer:
(car (cdr '(a b c)))
'b
But when I built the function:
(define test (lambda (list) (car (cdr (list)))))
(test '(a b c))
I get the following error:
. . application: not a procedure;
expected a procedure that can be applied to arguments
given: '(a b c)
arguments...: [none]
I really don't know what's this error means.
There are incorrect parentheses in your code, surrounding the list parameter - in Scheme this: (f) means "apply the f function with no arguments", so in your code this: (list) is trying to invoke the list parameter as if it were a function, which is not, raising an error.
Also notice that it's a bad idea to call list the parameter, there's already a built-in procedure with that name; that's why I renamed it to lst. This should fix it:
(define test
(lambda (lst)
(car (cdr lst))))
(test '(a b c))
=> b
This is #7 of of 99 Lisp problems: transform a list, possibly holding lists as elements into a `flat' list by replacing each list with its elements (recursively). I have tried several solutions, e.g from #2680864 or from here. They all work, but I run into a problem if I am flattening a list containing a quoted element. E.g.:
> '(a 'b c)
(A 'B C)
> '(a (quote b) c)
(A 'B C)
> (flatten '(a 'b c))
(A QUOTE B C)
In the latter case I would like to get:
(A 'B C)
It seems that the internal representation of ' gets in the way for this task! SBCL, CLISP, ECL, ... they all behave the same way.
Quoted elements in a list? That usually does not make sense. Why would you have it quoted?
(a b c) is a list of three symbols. Why would you quote elements in the list? like in (a 'b c)? Why? What would be the purpose of the quote?
In Common Lisp ' is a readmacro which expands 'a into (QUOTE A). Since this is a normal list, a typical flatten operation will collect the symbols QUOTE and A into the flat list. This is because a flatten function typicall checks whether something is an atom or not. If you don't want this, your flatten function needs to check if something is an atom or a two-element list with QUOTE as its first symbol.
But as I said above, the default usage is just to flatten symbols, since quoted symbols are usually not useful inside a list. You need to extend the flatten function otherwise.
For example:
(defun flatten (l &key (test #'atom))
(cond ((null l) nil)
((funcall test l) (list l))
(t (loop for a in l nconc (flatten a :test test)))))
CL-USER > (flatten '(a (('b) c) ('d) )
:test (lambda (item)
(or (atom item)
(and (eq (first item) 'quote)
(null (cddr item))))))
(A (QUOTE B) C (QUOTE D))