I'm having trouble understanding how Scheme forms and then detects lists. Hows does it determine the difference between a list and a dotted pair?
A list structure is formed from pairs. A proper list is a chain of pairs where the last pair has the empty list as its cdr.. We can make list? like this:
(define (list? lst)
(cond ((null? lst) #t)
((pair? lst) (list? (cdr lst)))
(else #f)))
Or you could use and/or:
(define (list? lst)
(or (null? lst)
(and (pair? lst)
(list? (cdr lst)))))
Related
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.
I'm fairly new to scheme and have been playing around with it and one of the problems I have placed upon myself is to remove all symbols from a single list of elements.
(define lst '(a 2 3 a 2 d 3))
(define removeSymbol
(lambda (lst)
(if (null? lst)
'()
(if (symbol? (car lst))
(removeSymbol (cdr lst))
(cons car lst) (removeSymbol (cdr lst))))))
(removeSymbol lst)
I feel like this should work, but it is not giving me what I am expecting.
My expectation: (list 2 3 2 3)
Any help or guidance would be appreciated.
You mentioned your unmet expectation, but not your result.
I'm guessing you're seeing a syntax error (in Racket, I get: if: bad syntax; has 4 parts after keyword) because the body of your nested if contains 3 s-expressions.
(if (symbol? (car lst))
(removeSymbol (cdr lst))
(cons car lst)
(removeSymbol (cdr lst)))
If you shuffle your parens so that they look like the following, your function should work as expected:
(define lst '(a 2 3 a 2 d 3))
(define (removeSymbol lst)
(if (null? lst)
'()
(if (symbol? (car lst))
(removeSymbol (cdr lst))
(cons (car lst) (removeSymbol (cdr lst))))))
(removeSymbol lst) ;; '(2 3 2 3)
I appreciate you're just working through this example as a learning exercise, but what you're attempting to do could also be achieved (arguably) a bit more idiomatically using the prelude functions filter, negate and symbol?:
(filter (negate symbol?) lst) ;; '(2 3 2 3)
Lets say I have a list containing arguments, how can I display it without the parentheses, example:
(define lst (list 1 2 3)) (display lst)
-> (1 2 3)
But I want it to appear as: 1 2 3
My attempt:
(define (clean-list lst)
(if
(null? lst) (display (null))
(display (car lst)))
(display #\space)
(clean-list (cdr lst)))
It returns the the list without parentheses, but with an error message... Anyone who could help me with this? Also note that im new to racket and racket is my first programming language. Appreciates all answers!
The error is caused by the fact that you always call recursively the function, after the if, even when the list is null.
Here is a correct version:
(define (clean-list lst)
(when (cons? lst)
(display (car lst))
(display #\space)
(clean-list (cdr lst))))
Note that this function prints only the elements on the first level of the list without parentheses, but if an element is a list it is printed with parentheses.
I have been working in DrRacket, trying to create a "prefix" function (#lang racket). It should take two lists as an input, and should output #t if pf is either null, or is equal to the beginning of ls.
My problem is that my code doesn't seem to return anything at all when pf is not a prefix of ls and ls isn't null. If I replace the #f in the if statement with something else, like '(), it will return that properly, but if I try to capture the '() and give an output based on that instead, it gives results that don't make sense (like saying that '() isn't null, or that '() doesn't equal '()). It seems to have something to do with having an if statement within a cond statement. Could anyone tell me what it's doing, or why? Is it possible to make this code work correctly, or am I going to need to rework it another way?
Thanks for the help!
(define prefix
(lambda (pf ls)
(cond
[(null? pf) #t]
[(null? ls) #f]
[(if (equal? (car pf) (car ls)) (prefix (cdr pf) (cdr ls)) #f)])
))
Having an if within a cond condition is usually a sign of doing something wrong. I think you meant to say this:
(define prefix
(lambda (pf ls)
(cond
[(null? pf) #t]
[(null? ls) #f]
[(equal? (car pf) (car ls)) (prefix (cdr pf) (cdr ls))]
[else #f])))
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.