I'm writing a function that merges two lists. If one of the list's item is a list, I need to extract it too.
list1:'(1 (2 3 4) 5 6))
list2: '(7 (8 9) 10 (11))
output: (1 2 3 4 5 6 7 8 9 10 11)
I tried to solve it by my code doesn't work. What is the problem?
(define (merge lis1 lis2)
(define (combine lis fine)
(cond
((null? lis) lis)
((list? lis) (combine (car lis) fine) (combine (cdr lis) fine))
(else (cons lis fine))))
(cond
(combine (cons lis2 lis1) '())))
The easiest way is to simply use the library function flatten.
(define (merge lis1 lis2)
(flatten (cons lis1 lis2)))
flatten takes a list that can contain lists (who in turn can contain more lists, ...) and flattens the result into a list of non-lists, which is what your combine function seems to be trying to do.
(flatten '(1 2 (3 (4 5) 6))) returns '(1 2 3 4 5 6)
If this library function is off limits, your code is actually pretty close to correct.
The first issue is on the ((list? lis) (combine (car lis) fine) (combine (cdr lis) fine) ) line. fine is never changed, so the code evaluates (combine (car lis) fine) and then returns (combine (cdr lis) fine), where the fine in the second expression is the original value of fine. This line is the same thing as ((list? lis) (combine (cdr lis) fine) ), which is obviously not what we want. Instead, we have to use the first expression inside the second expression ((list? lis) (combine (cdr lis) (combine (car lis) fine))).
The second issue is that, in combine, when lis is null, we need to return fine, not lis.
The next issue is that this code goes through the list, takes the first element of lis and puts it on the front of fine, and then passes the newly created list and uses it for the next iteration of the function, where it takes second value in lis and sticks it on the front of the new fine, in front of the first value of lis. The results in the order of the return value of fine being reversed -- (merge '(1 2 (3)) '(4 (5 6))) will return (6 5 4 3 2 1). We have two choices: we can call reverse on the return from combine in the body of merge or we can invert the line we changed above, making it ((list? lis) (combine (car lis) (combine (cdr lis) fine))). This means that we would add the rest of the list to fine before adding the current element, which is what we want.
Another issue is that we need to cons lis1 to lis2, not the other way around.
The final issue is that the cond in the body of merge is unnecessary -- we can remove it.
As a side note, it is generally considered neater to not give close parentheses a new line and indent the body of a define or cond by just two spaces.
With all of these changes, the final code is:
(define (merge lis1 lis2)
(define (combine lis fine)
(cond
((null? lis) fine)
((list? lis) (combine (car lis)
(combine (cdr lis) fine)))
(else (cons lis fine))))
(combine (cons lis1 lis2) '()))
Related
How I can replace an append with a cons in my lisp program that reverses a list and all it's substrings?
(defun revert (l)
(cond
((atom l) l)
(t (append (revert (cdr l))
(list (revert (car l)))))))
(write (revert '(2 3 5 6 7 8 9 (4 5 (6)))))
With append the result is:
(((6) 5 4) 9 8 7 6 5 3 2)
By replacing append with cons i get something like this:
((((((((NIL (((NIL (NIL 6)) 5) 4)) 9) 8) 7) 6) 5) 3) 2)
I tried to watch some youtube tutorials but I still don't know how to do it correctly
As you have seen, you cannot simply replace append with cons, because they are two very different operators: append concatenates two lists in a single list, while cons takes an element and a list and returns a new list with the element in first position, and the rest of the list the second parameter.
One very simple way of solving your problem is simply to define your version of append using cons. For instance:
(defun my-append (list1 list2)
(cond ((null list1) list2)
(t (cons (car list1) (my-append (cdr list1) list2))))))
and the substituting append with my-append in the revert function.
Another way, is to define a new function that takes two lists and reverses the first one to the beginning of the second one. For instance:
(defun revert (l)
(rev2 l nil))
(defun rev2 (l1 l2)
(cond ((null l1) l2)
((atom (car l1)) (rev2 (cdr l1) (cons (car l1) l2)))
(t (rev2 (cdr l1) (cons (revert (car l1)) l2)))))
I am learning Racket for understanding principles of programming languages. What I am doing is to add only second elements in pairs of a list. In my understanding, I think I am doing correctly. However, the error message shows up. Please provide me any advise to understand what I am doing wrong.
(define pairs
'((1 5)(6 4)(7 8)(15 10)))
(define (secondSum lst)
(if (null? lst) 0
(+ (cdr (car lst)) (secondSum (cdr lst)))
)
)
>(secondSum pairs)
+: contract violation
expected: number?
given: '()
argument position: 2nd
other arguments...:
10
What I am looking for is
(5 + 4 + 8 + 10)
(cdr (car lst)) should be (car (cdr (car lst))) also (cadr (car lst)) or in racket preferred (second (first lst)) that is if lst is '((1 5)) the result should be 5.
I had to be sure this was right so I ran the program with the fix and verified the result:
(define pairs '((1 5)(6 4)(7 8)(15 10)))
(define (secondSum lst)
(if (null? lst) 0
(+ (car (cdr (car lst))) (secondSum (cdr lst)))
)
)
(secondSum pairs)
(+ 5 4 8 10)
The last two expressions both have the value 27.
I need some one can explain for me to how to do this please
Define a function that takes two arguments, a list of numbers and a single number (the threshold). It should return a new list that has the same numbers as the input list, but with all elements greater than the threshold number removed. You may not use the built-in filter function as a helper
function. Your implementation must be recursive.
INPUT: A list of numbers and a single atomic number.
OUTPUT: A new list of numbers that contains only the numbers from the original list that are strictly “less than” (<), i.e. below the threshold number.
Example:
> (upper-threshold '(3 6.2 7 2 9 5.3 1) 6)
'(3 2 5.3 1)
> (upper-threshold '(1 2 3 4 5) 4)
'(1 2 3)
> (upper-threshold '(4 8 5 6 7) 6.1)
'(4 5 6)
> (upper-threshold '(8 3 5 7) 2)
'()
This what I have so far but I receve error
(define (upper-threshold pred lst)
(cond [(empty? lst) empty]
[(pred (first lst))
(cons (first lst) (upper-threshold pred (rest lst)))]
[else (upper-threshold pred (rest lst))]))
; (threshold (lambda (x) (> x 5)) '(1 6 7))
Your implementation doesn't have the same arguments as your assignment.
You need something that compares the first element with the second argument so see it its larger or not, then either (cons (car lst) (upper-treshold (cdr lst) streshold)) to include the first element in the result or (upper-treshold (cdr lst) treshold) to not include it.
(define (upper-threshold lst treshold)
(cond [(empty? lst) empty]
[(> (car lst) treshold)
(cons (first lst) (upper-threshold (rest lst) treshold))]
[else (upper-threshold (rest lst) treshold)]))
I don't quite understand your code. However, you might be looking for something like this:
(define (upper-threshold lst theshold)
(cond
((null? lst) '())
((< (car lst) theshold)
(cons (car lst)
(upper-threshold (cdr lst) theshold)))
(else (upper-threshold (cdr lst) theshold))))
If your purpose is to implement the standard function filter, perhaps you should write the code some another way.
It appears that you've taken a filter function and renamed it as upper-threshold. It's true that these two are related. I would suggest trying to build upper-threshold from scratch, using the design recipe:
http://www.ccs.neu.edu/home/matthias/HtDP2e/
When you get confused, refer to existing functions that you have, including the definition of filter that you have here. Your example may be slightly harder to understand because it uses lambda.
I have to make a recursive function in lisp which takes a list and makes another list with only the elements on odd position in the given list.
If I have (1 2 3 4 5) I have to output (1 3 5)
I have a code here:
(defun pozpar(lst) (do(
(l lst (cddr l))
(x '() (cons x (car l))))
((null l) x)))
This outputs:
(5 3 1)
I know cons adds the elements at the beginning and I tried with append or list but nothing worked.
I think this is a way easier solution:
(defun popzar (lst)
(cond ((null lst) nil)
(t (cons (car lst)
(popzar (cdr (cdr lst)))))))
It first checks if the list is empty and if not it creates a new list with the first element and the result of calling itself again with the rest of the list except for the second element.
The easiest way is to reverse the result:
(defun pozpar (lst)
(do ((l lst (cddr l))
(x '() (cons (car l) x)))
((null l)
(nreverse x))))
(pozpar '(1 2 3 4 5))
==> (1 3 5)
Notes
This returns, not outputs the value you want.
Prepending values and reverting the result is a common Lisp coding pattern.
Since append is linear in the length of its argument, using it in a loop produces quadratic code.
I formatted the code in the standard Lisp way. If you use this style, lispers will have an easier time reading your code, and, consequently, more willing to help you.
With using loop it's very easy to get the elements in the order you processed them. It is also the most effective and the only one guaranteed to work with all length arguments:
(defun pozpar1 (lst)
(loop :for e :in lst :by #'cddr
:collect e)))
If you really want recursion I would have done it with an accumulator with a linear update reverse in the end:
(defun pozpar2 (lst)
(labels ((helper (lst acc)
(if (endp lst)
(nreverse acc)
(helper (cddr lst) (cons (car lst) acc)))))
(helper lst '())))
However a classical not tail recursive version would look like this:
(defun pozpar3 (lst)
(if (endp lst)
'()
(cons (car lst) (pozpar3 (cddr lst)))))
This is an exercise from EOPL.
Procedure (invert lst) takes lst which is a list of 2-lists and returns a list with each 2-list reversed.
(define invert
(lambda (lst)
(cond((null? lst )
'())
((= 2 (rtn-len (car lst)))
( cons(swap-elem (car lst))
(invert (cdr lst))))
("List is not a 2-List"))))
;; Auxiliry Procedure swap-elements of 2 element list
(define swap-elem
(lambda (lst)
(cons (car (cdr lst))
(car lst))))
;; returns lengh of the list by calling
(define rtn-len
(lambda (lst)
(calc-len lst 0)))
;; calculate length of the list
(define calc-len
(lambda (lst n)
(if (null? lst)
n
(calc-len (cdr lst) (+ n 1)))))
This seems to work however looks very verbose. Can this be shortened or written in more elegant way ?
How I can halt the processing in any of the individual element is not a 2-list?
At the moment execution proceed to next member and replacing current member with "List is not a 2-List" if current member is not a 2-list.
The EOPL language provides the eopl:error procedure to exit early with an error message. It is introduced on page 15 of the book (3rd ed.).
The EOPL language does also include the map procedure from standard Scheme. Though it may not be used in the book, you can still use it to get a much shorter solution than one with explicit recursion. Also you can use Scheme's standard length procedure.
#lang eopl
(define invert
(lambda (lst)
(map swap-elem lst)))
;; Auxiliary Procedure swap-elements of 2 element list
(define swap-elem
(lambda (lst)
(if (= 2 (length lst))
(list (cadr lst)
(car lst))
(eopl:error 'swap-elem
"List ~s is not a 2-List~%" lst))))
So it seems that your version of invert actually returns a list of different topology. If you execute (invert ...) on '((1 2) (3 4)), you'll get back '((2 . 1) (4 . 3)), which is a list of conses, not of lists.
I wrote a version of invert that maintains list topology, but it is not tail-recursive so it will end up maintaining a call stack while it's recursing.
(define (invert lst)
(if (null? lst)
lst
(cons (list (cadar lst) (caar lst))
(invert (cdr lst)))))
If you want a version that mimics your invert behavior, replace list with cons in second to last line.
If you want it to exit early on failure, try call/cc.
(call-with-current-continuation
(lambda (exit)
(for-each (lambda (x)
(if (negative? x)
(exit x)))
'(54 0 37 -3 245 19))
#t))
===> -3
(Taken from http://www.schemers.org/Documents/Standards/R5RS/HTML/r5rs-Z-H-9.html#%_idx_566)
What call-with-current-continuation (or call/cc, for short) does is pass the point where the function was called in into the function, which provides a way to have something analogous to a return statement in C. It can also do much more, as you can store continuations, or pass more than one into a function, with a different one being called for success and for failure.
Reverse list containing any number or order of sub-lists inside.
(define (reverse! lst)
(if (null? lst) lst
(if (list? (car lst))
(append (reverse! (cdr lst)) (cons (reverse! (car lst)) '()))
(append (reverse! (cdr lst)) (list (car lst))))))