I have been listening to Stanford's programming paradigm lecture series, but I'm confused by the following code (from lecture 20). Would someone explain, line by line, what this is doing?
Thanks.
(define (flatten sequence)
(cond ((null? sequence) '())
((list? (car sequence)) (append (flatten (car sequence))
(flatten (cdr sequence))))
(else (cons (car sequence)
(flatten (cdr sequence))))))
# define a procedure 'flatten' that takes a list 'sequence'
(define (flatten sequence)
# if the 'sequence' is empty, return an empty list
(cond ((null? sequence) (list))
# if the first element of 'sequence' is itself a list, return a new list
# made by appending the flattened first element of 'sequence' with the
# flattened rest of the 'sequence'
((list? (car sequence))
(append (flatten (car sequence))
(flatten (cdr sequence))))
# if the first element of 'sequence' is not a list, return a new list
# made by cons-ing that element with the flattened rest of the 'sequence'
(else
(cons (car sequence)
(flatten (cdr sequence))))))
I pretty-printed it (inserted some newlines and indented the code to show its structure) and also replaced '() with (list) (which has the same value) just to prevent the code from being highlighted incorrectly.
+1 what is cons-ing? I'd appreciate if you explain other keywords as well. thanks
When I say cons-ing I'm just referring to the cons procedure. When you see (cons <expression> <list>) where <expression> is any Scheme expression or value and <list> is any Scheme expression that evaluates to a list, cons will return the <list> with the value of the <expression> tacked on the front of it. For example, (cons 1 (list 2 3 4)) returns the list (list 1 2 3 4). In fact, (list 1 2 3 4) in Scheme is just a short way of writing (cons 1 (cons 2 (cons 3 (cons 4 '() )))).
The other two words you might have trouble with are car and cdr. You can think of (car <list>) as meaning the first element or head of the <list>, and (cdr <list>) as meaning the rest of the elements or tail of the <list>. For example, (car (list 1 2 3 4)) returns the value 1, and (cdr (list 1 2 3 4)) returns the list (list 2 3 4).
If you need any help with other keywords, let me know.
define function to flatten a
sequence
For the empty sequence, return empty
if the head (car) of the list is a
sequence return the result of
flattening it appended to the
flattening of the tail (cdr)
else append the head to the flatting
of the tail
Related
I am new in Racket and I was assigned to do my own filter procedure. It should work similar to the Racket filter procedure. Currently, my-filter has two arguments: the even procedure to check the items in the list, and a list of items.
So far, I have been only able to check whether the items in the list are even or not. my-filter is supposed to iterate through a list of numbers, retrieve the numbers that are even and save them in a second list. How can I iterate through the list and store the even numbers in the second list?
(define (my-filter f lst)
(if (empty? lst)
empty
(cons
(f (first lst))
(my-filter f (rest lst)))))
> (my-filter even? '(1 2 3 4 5 6))
'(#f #t #f #t #f #t)
There are three cases that you need to consider:
Input list is empty -> we're done.
Current element satisfies the predicate function -> add it to the output and continue with next element.
Current element doesn't satisfy the predicate function -> skip it and continue with next element.
You're mixing the last two cases into a single case. And notice that you must not add (f (first lst)) to the output, that's just the condition that we want to evaluate, we should add (first lst) instead. This is what I mean:
(define (my-filter f lst)
(cond ((empty? lst) empty)
((f (first lst))
(cons (first lst) (my-filter f (rest lst))))
(else (my-filter f (rest lst)))))
It works as expected:
(my-filter even? '(1 2 3 4 5 6))
=> '(2 4 6)
Ultimately, i shall be trying to reimplement sorting algorithms in scheme for linked lists. I have written a subprocedure that will help me along the way. The goal is to simply swap 2 elements, given as arguments "pair1 and pair2" and then return the list.
(define (cons-til lst until)
(cond
((or (null? lst) (eq? (car lst) until)) '())
(else (cons (car lst) (cons-til (cdr lst) until)))))
(define (swap lst pair1 pair2)
(cons (cons (append (cons-til lst (car pair1))
(car pair2)) (car pair1)) (cdr pair2)))
(define my-list '(1 2 3 4 5 6 7))
(swap my-list (cdr (cdr my-list)) (cdr (cdr (cdr my-list))))
When the code is executed, it returns:
(((1 2 . 4) . 3) 5 6 7)
How can i fix this in order to have a plain scheme list. The element seems to have swapped correctly.
Two suggestions:
Do you really want to write n cdr calls to index the nth element? I recommend strongly using integer indexes (if you need them, that is).
Referring to elements by index in a linked list (i. e. “random access”) is not very efficient most of the time, especially when done in loops. I strongly recommend using either vectors or a better suited algorithm that doesn't need random access, e. g. merge sort.
(define (swap2 lst pair1 pair2)
(append (append (append (cons-til lst (car pair1))
(list (car pair2)))
(list (car pair1))) (cdr pair2)))
This code seems to work. I'm not sure this is completely efficient or a smart solution to the problem. Looking forward to other suggestions. The value given back is '(1 2 4 3 5 6 7)
I am trying to extract all elements that are of symbol 'sym
from a list.
(define (extract-sym list)
extract-sym-inner (list null))
(define (extract-sym-inner oldList newList)
(cond (null? oldList
(newList))
(eq? (car oldList) newList
(extract-sym-inner((cdr oldList) append newList (extract-sym(oldList)))))
(eq? (car oldList) 'sym
(extract-sym-inner((cdr oldList) cons newList(car oldList))))
(else
(extract-sym-inner(cdr oldList newList)))))
What I'm trying to do is:
Send the list into an inner function and then:
1. if it's null, return the new list
2. else if the element itself is a list, append the list from the outer function to the new list and continue to next element of old list
3. else if the element is of symbol 'sym, insert it to the new list and continue to the next element of old list
4. else continue to the next element of old list
I think the algorithm itself should work, but I can't manage to understand all the compilation errors I'm getting. For example (extract-sym '(1 2 sym)) gives me the error application: not a procedure;
Any comment would help..
There are lots of syntax errors in your code (mostly dealing with incorrect usage of brackets). As mentioned in the comments, you should spend some time familiarizing yourself with the syntax of the language before tackling any other problem. Having said that, this is what I believe you intended to do, study the following solution and pay attention to those brackets!
(define (extract-sym lst) ; don't use "list" as a parameter name
(cond ((null? lst) '()) ; if list is empty, return empty list
((eq? (car lst) 'sym) ; if current element is 'sym
(cons (car lst) ; add it to the output using cons
(extract-sym (cdr lst)))) ; and advance recursion
((pair? (car lst)) ; if current element is a list
(append (extract-sym (car lst)) ; recursively process and use append
(extract-sym (cdr lst)))) ; also, advance recursion
(else (extract-sym (cdr lst))))) ; otherwise just advance recursion
For example:
(extract-sym '(1 sym 2 (3 sym 4) (5) sym))
=> '(sym sym sym)
Pretty straightforward question. My initial approach was to define another procedure to find the last element of lst within first-last. After finding the last element I appended it with the first element of lst (car lst).
This is how append works.
(append list1 list2)
e.g., (append '(1 2 3) '(2 1 5)) -> (1 2 3 2 1 5)
I'm wondering if the problem is just with my syntax but I am not sure.
(define (first-last lst)
(define (last lst)
(cond ((null? (cdr lst))(car lst))
(else (last (cdr lst)))))
(append(car lst)(last lst)))
The error occurs in the
(append(car lst)(last lst)))
"mcar: contract violation
expected: mpair?
given: 1"
This is my first question on stack, so I'm sorry if the question is not presented in the correct way.
append is only for joining two or more lists. Here, though, you're not joining existing lists, but building a list from two elements. For that, use list:
(list (car lst) (last lst))
If you can use match, a neat solution is possible:
(define first-last
(lambda (x)
(match x
((first rest ... last)
(list first last))
((only) (list only only))
(_ #f))))
Of course, you could return something other than #f in the catch-all clause.
So I have to remove the last element of a list in scheme.
For example, let's say I have a list (1 2 3 4). I need to return:
(1 2 3)
My idea:
reverse(list)
car(list)
reverse(list)
Is there a reverse function in scheme(racket)?
You wrote: "reverse, car, reverse". I believe you meant to write "reverse, cdr, reverse". There's nothing wrong with this solution; it's linear in the size of the list, just like any solution to this that uses the standard lists.
As code:
;; all-but-last: return the list, not including the last element
;; list? -> list?
(define (all-but-last l) (reverse (cdr (reverse l))))
If the multiple traversal of the list or the needless construction of another list copy bothers you, you can certainly avoid it, by writing the thing directly.
Given your almost-solution, I'm going to assume that this isn't homework.
Here's what it would look like, in racket:
#lang racket
(require rackunit)
;; all-but-last : return the list, except for the last element
;; non-empty-list? -> list?
(define (all-but-last l)
(cond [(empty? l) (error 'all-but-last "empty list")]
[(empty? (rest l)) empty]
[else (cons (first l) (all-but-last (rest l)))]))
(check-equal? (all-but-last '(3 4 5))
'(3 4))
There is a reverse, but using it would not be very efficient. I suggest the following recursive function.
(define (remove-last lst)
(if (null? (cdr lst))
'()
(cons (car lst) (remove-last (cdr lst)))))
(remove-last '(1 2 3 4)) ; returns '(1 2 3)
The if checks whether it is at the last element of the list.
SRFI 1 (activate in Racket using (require srfi/1)) has a drop-right function:
(drop-right '(1 2 3 4) 1) ; => (1 2 3)
I would do a recursive function that goes down the list and attaches the element (using cons) if the element after it is not the last, and appends nothing if it isn't.
I haven't done scheme for years though so that's as far as I can go.
Someone can run with how to implement it (unless it's homework then they probably shouldn't!)
I've done something simpler than: reverse(list), car(list), reverse(list) to get the last element, check out:
(define (last-one liste)
(if(null? (cdr liste))
null
(cons (car liste) (last-one (cdr liste)))
)
)
Those who are looking for another way can check this out:
(define (removing-last xx)
(remove (list-ref xx (- (length xx) 1)) xx))
I would write a simple recursion, altering the typical "empty? mylist" base case to "empty? (rest mylist)," so that I can return empty when the input list is only 1 element.
(define (removelast mylist)
(cond
[(empty? (rest mylist)) empty]
[(cons? mylist) (cons (first mylist) (removelast (rest mylist)))]))
(removelast (list 1 2 3 4 5))
By the way, this code is in Racket/PLT Scheme, a subset of Scheme.