Checking if lists are equal Scheme [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 4 years ago.
This assignment is to check if both lists are equal by creating my own function to do so, with this i am getting it to define the function. The issue i am having is when i try to call the function using (listEquals list1 list2) it is returning an error of
application: not a procedure;
expected a procedure that can be applied to arguments
given: #f
I am giving a input of two lists list1 = (1 2 3 4), list2 = (2 3 4 5).
Here is my current implimentation
(define listEquals (lambda (list1 list2)
(if (eq? list1 null)
(if (eq? list2 null)
(true)
(false))
(if (eq? list2 null)
(false)
(if (eq? (first list1) (first list2))
(listEquals (rest list1) (rest list2))
(false))))))

You must not surround true, false with brackets, they're not procedures, hence they can not be applied. Try this:
(define listEquals
(lambda (list1 list2)
(if (eq? list1 null)
(if (eq? list2 null)
true
false)
(if (eq? list2 null)
false
(if (eq? (first list1) (first list2))
(listEquals (rest list1) (rest list2))
false)))))

You've already accepted an answer, but here's a different approach that doesn't involve conditionals.
Two lists are equal if an only if
Either both are empty or both are non-empty, and
they are empty, or
their first elements are equal, and their tails are equal
In scheme:
(define (list-equals ls1 ls2)
(and (equal? (empty? ls1) (empty? ls2))
(or (empty? ls1) ; Only need to check one since they're equal
(and (eq? (first ls1) (first ls2))
(list-equals (rest ls1) (rest ls2))))))

Related

How can I recursively check if a list is sorted in Lisp?

I want to write a recursive function that checks the list and either returns true if the list is in ascending order or NIL otherwise. If the list is empty it is still true. I am completely new to Lisp, so its still very confusing.
(defun sorted (x)
(if (null x)
T
(if (<= car x (car (cdr x)))
(sorted (cdr x))
nil)))
The recursive version:
(defun sorted (list)
(or (endp list)
(endp (cdr list))
(and (<= (first list) (second list))
(sorted (cdr list)))))
The more idiomatic loop-based predicate accepting a :test argument:
(defun sortedp (list &key (test #'<=))
(loop for (a b) on list
while b
always (funcall test a b)))
The version accepting a :key; we only call the key function once per visited element:
(defun sortedp (list &key (test #'<=) (key #'identity))
(loop for x in list
for old = nil then new
for new = (funcall key x)
for holdp = T then (funcall test old new)
always holdp))
Some tests:
(loop for k in '(()
((1))
((1) (2))
((2) (1))
((1) (2) (3))
((3) (2) (1)))
collect (sortedp k :test #'> :key #'car))
=> (T T NIL T NIL T)
This one also works with other kinds of sequences:
(defun sortedp (sequence &key (test #'<=) (key #'identity))
(reduce (lambda (old x &aux (new (funcall key x)))
(if (or (eq old t)
(funcall test old new))
new
(return-from sortedp nil)))
sequence
:initial-value t))
The above test gives:
(T 1 NIL 1 NIL 1)
... which is a correct result thanks to generalized booleans.
If you are doing your homework (seems so), then the above answers are fine. If you are just learning Lisp, and don't have constraints about recursivity, then the following might give you a glimpse about the power of Lisp:
(defun sorted (l)
(or (null l) (apply #'< l)))
The first problem with your solution is the base case You need to stop not at the end of the list, but when looking at the last to elements, as you need to elements to do the comparison. Also the parens are missing in the call to (car x)
(defun sorted (list)
(if (endp (cddr list))
(<= (car list) (cadr list))
(and (<= (car list) (cadr list))
(sorted (cdr list)))))
Bare in mind that recursive solutions are discouraged in CL

Multiplication of two unary lists based on the addition function

(define unary-add
(lambda (list1 list2)
(if (pair? list1)
(cons (car list1)
(unary-add (cdr list1) list2))
list2)))
I performed the addition of two unary representations of lists as above. Now I want to multiply them, considering multiplication as the repeated addition.
So, I made use of this function, and did the below:
(define unary-mul
(lambda (list1 list2)
(if (pair? list1)
(cons (car list1)
(unary-mul (unary-add (cdr list1) list2)))
list2)))
On running the code, it says arguments do not match. Where did I went wrong?
Your current approach doesn't seem right - the recursive call is misplaced, and the error reported indicates that you forgot to pass the second parameter to unary-mul. Try this instead:
(define unary-mul
(lambda (list1 list2)
(if (pair? list2)
(unary-add list1
(unary-mul list1 (cdr list2)))
'())))
Explanation: a multiplication is just a repeated addition, in the above code we keep adding list1 and decreasing the length of list2 until it's empty. It works as expected:
(unary-mul '(x x x) '(x x))
=> '(x x x x x x)

I need to merge two lists in Scheme, taking one element from each one

This is what I've written:
(: mmm : (Listof Any) (Listof Any) -> (Listof Any))
(define (mmm list1 list2)
(cond [(or (null? list1) (null? list2)) null]
(and (cons (first list1) (first list2)) (mmm (rest list1) (rest list2)))))
I'll give you an example:
list1: a b c
list2: 1 2 3
answer: ((a 1) (b 2) (c 3))
edited
they both same size
If you are allowed to use map, you can use:
(define (mmm lst1 lst2) (map (lambda (x y) (list x y)) lst1 lst2))
There are a couple of problems with your code:
The base case might or might not be right - if the input lists are guaranteed to be of the same size, then it's fine. If they can be of different size see #Sylwester's answer for advice
The second condition should start with an else (because it's the last one and the conditions are mutually exclusive), not with and
You are not building the output list correctly. The new element to be added is a list with the first element of both input lists, and that must be consed to the result of calling the recursion
To fix them, try this - assuming input lists of equal length:
(define (mmm list1 list2)
(cond [(or (null? list1) (null? list2)) null]
[else (cons (list (first list1) (first list2))
(mmm (rest list1) (rest list2)))]))
Now the procedure works as expected:
(mmm '(a b c ) '(1 2 3))
=> '((a 1) (b 2) (c 3))
If you know the lists are the same size, then it becomes simply:
(define (mmm list1 list2) (map list list1 list2))
Note: Replace map list with map cons if that is what you really want. Your code used cons but your result example suggests that list is what you want.

Multiplying numbers in a list (coordinate-wise) without using mapcar in Lisp

I'm having trouble with the output of my code, I think it's when I'm checking conditions for the null of my lists.
The question I am trying to complete is: Write a function vecmul that will take as inputs two simple lists of numbers. vecmul should multiply these lists coordinate-wise as one would multiply vectors. Assume the two lists are the same length. [For example, (vecmul '(2 3 4 5) '(1 4 5 2)) returns (2*1 3*4 4*5 5*2) or (2 12 20 10). You are not allowed to use mapcar for this function]
So far I have
(defun vecmul (list list2)
(cond ((null list) 0)
(t (cons (* (car list) (car list2))
(vecmul (cdr list) (cdr list2))))))
[170]> (setq l '(2 4 6))
(2 4 6)
[171]> (setq r '(1 3 5))
(1 3 5)
[172]> (vecmul l r)
(2 12 30 . 0)
I'm getting the correct numbers, it's just that the list is adding the "." and the "0" at the end of the list. I'm pretty sure it's because i'm not stopping the recursion right or not working the cond right. I'm just not entirely sure how to correct it.
You've got it almost right. However, you're terminating your list with 0, when the correct termination is nil. This code works:
(defun vecmul (list list2)
(cond ((null list) nil)
(t (cons (* (car list) (car list2)) (vecmul (cdr list) (cdr list2))))))
When you call (cons 1 2), the cons cell you get is written (1 . 2). the notation (1 2 3 4 5) is just shorthand for (1 . (2 . (3 . (4 . (5 . nil))))). If the cdr of the last cons cell is 6, not nil, then you get (1 . (2 . (3 . (4 . (5 . 6))))), which shortens to (1 2 3 4 5 . 6).
Neil Forrester answered your question.
Some more remarks. Use modern names in Lisp: first and rest.
(defun vecmul (list1 list2)
(cond ((null list1) nil)
(t (cons (* (first list1) (first list2))
(vecmul (rest list1) (rest list2))))))
If you have a simple true and false decision, IF might be better. Since list operations are involved, I would write it as the following and not use WHEN.
(defun vecmul (list1 list2)
(if (null list1)
nil
(cons (* (first list1) (first list2))
(vecmul (rest list1) (rest list2)))))
Best use a loop construct or mapping in real code. Recursion, as above, has a stack depth limit. A loop does not have that restriction.
(defun vecmul (list1 list2)
(loop for e1 in list1 and e2 in list2
collect (* e1 e2)))
or
(defun vecmul (list1 list2)
(mapcar #'* list1 list2))

LISP: multi-level recursive reverse function

How to reverse a list such that every sublist is also reversed? This is what I have so far:
(defun REV (L)
(cond
((null L) nil)
((listp L)
(append
(REV (cdr L))
(list (car L))))
(t
(append
(REV (cdr L))
(list (car L))))))
You are on the right track, but your last two conditions have the same action, which should give an indication that one of them is not doing what it should. Indeed, the second condition, the listp case, is not right, because when it's a list, you need to append the reverse of that list instead of the unmodified list. A possible solution:
(defun my-reverse (l)
(cond ((null l) nil)
((listp (car l)) (append (my-reverse (cdr l))
(list (my-reverse (car l)))))
(t
(append (my-reverse (cdr l))
(list (car l))))))
> (my-reverse '((1 2 3) (4 5 6)))
((6 5 4) (3 2 1))
As you can see, the only difference is that you test if the first element is a list, and if it is, you reverse the first element before appending it.
I'd write it this way:
(defun reverse-all (list)
(loop
with result = nil
for element in list
if (listp element)
do (push (reverse-all element) result)
else do (push element result)
finally (return result)))
Sounds like a homework problem :)
Looks like you started by writing the regular reverse code. I'll give you a hint: The second condition (listp L) isn't quite right (it'll always be true). You want to be checking if something else is a list.
dmitry_vk's answer (which probably is faster in most lisps than using append in the previous examples) in a more lispish way:
(defun reverse-all (list)
(let ((result nil))
(dolist (element list result)
(if (listp element)
(push (reverse-all element) result)
(push element result)))))
Or even:
(defun reverse-all (list)
(let ((result nil))
(dolist (element list result)
(push
(if (listp element) (reverse-all element) element)
result))))