Replacing symbols in a (nested)? List in LISP - common-lisp

I am supplying a list in the following format:
(test '((Q H)(A D)(J C)(Q S)(3 S)))
The aim is to to search through the list and replace the symbols J Q K and A with the respective numbers 11 12 13 and 14. Currently my function is this (I'm sorry):
(defun test (hand)
(cond ((equal (first (first hand)) 'J)
(setf (first (first hand)) '11))
((equal (first (first hand)) 'Q)
(setf (first (first hand)) '12))
((equal (first (first hand)) 'K)
(setf (first (first hand)) '13))
((equal (first (first hand)) 'A)
(setf (first (first hand)) '14))
(t (print '(It's ogre now))))
(cond ((equal (first (second hand)) 'J)
(setf (first (second hand)) '11))
((equal (first (second hand)) 'Q)
(setf (first (second hand)) '12))
((equal (first (second hand)) 'K)
(setf (first (second hand)) '13))
((equal (first (second hand)) 'A)
(setf (first (second hand)) '14))
(t (print '(It's ogre now))))
(cond ((equal (first (third hand)) 'J)
(setf (first (third hand)) '11))
((equal (first (third hand)) 'Q)
(setf (first (third hand)) '12))
((equal (first (third hand)) 'K)
(setf (first (third hand)) '13))
((equal (first (third hand)) 'A)
(setf (first (third hand)) '14))
(t (print '(It's ogre now))))
(cond ((equal (first (fourth hand)) 'J)
(setf (first (fourth hand)) '11))
((equal (first (fourth hand)) 'Q)
(setf (first (fourth hand)) '12))
((equal (first (fourth hand)) 'K)
(setf (first (fourth hand)) '13))
((equal (first (fourth hand)) 'A)
(setf (first (fourth hand)) '14))
(t (print '(It's ogre now))))
(cond ((equal (first (fifth hand)) 'J)
(setf (first (fifth hand)) '11))
((equal (first (fifth hand)) 'Q)
(setf (first (fifth hand)) '12))
((equal (first (fifth hand)) 'K)
(setf (first (fifth hand)) '13))
((equal (first (fifth hand)) 'A)
(setf (first (fifth hand)) '14))
(t (print '(It's ogre now))))
(print hand))
I am certain there is a cleaner way of doing this. Could anyone point me in the right direction?

As you want to replace all occurrences of J/Q/K/A with the corresponding numbers, you can use the SUBST function:
(subst 11 'J (subst 12 'Q (subst 13 'K (subst 14 'A hand))))
or, with a loop, which would look nicer if you had more things to substitute:
(loop for (letter value) in '((J 11) (Q 12) (K 13) (A 14))
for hand% = (subst value letter (or hand% hand))
finally (return hand%))

Lets do this. [dons code-review hat]
Firstly, your procedure is going to mutate its input, and that's considered bad style.
CL-USER> (defun test (hand)
...
(print hand))
TEST
CL-USER> (defparameter *a-hand* '((Q H)(A D)(J C)(Q S)(3 S)))
*A-HAND*
CL-USER> (test *a-hand*)
(IT 'S OGRE NOW)
((12 H) (14 D) (11 C) (12 S) (3 S))
((12 H) (14 D) (11 C) (12 S) (3 S))
CL-USER> *a-hand*
((12 H) (14 D) (11 C) (12 S) (3 S))
CL-USER>
This is because you're using setf all over the place to mutate your argument. The alternative to performing that mutation is to build up a new list of pairs with the first element replaced by its numeric representation. Building up a new list with some transformation applied to it happens to be the purpose of the mapcar function in Common Lisp. In order to apply that strategy, we need to figure out what it is that you're doing to each element of the incoming list. The pattern should be obvious from the above:
...
(cond ((equal (first (first hand)) 'J)
(setf (first (first hand)) '11))
((equal (first (first hand)) 'Q)
(setf (first (first hand)) '12))
((equal (first (first hand)) 'K)
(setf (first (first hand)) '13))
((equal (first (first hand)) 'A)
(setf (first (first hand)) '14))
(t (print '(It's ogre now))))
...
So. Lets get a separate function that takes a list and sometimes replaces its first element by some number.
(lambda (lst)
(cond ((equal (first lst) 'J)
(cons '11 (cdr lst)))
((equal (first lst) 'Q)
(cons '12 (cdr lst)))
((equal (first lst) 'K)
(cons '13 (cdr lst)))
((equal (first lst) 'A)
(cons '14 (cdr lst)))
(t lst)))
Note that we've replaced (first (first hand)) with a reference to our argument (first lst), and that we now use cons to build a new list with a replacement element at the first position. We can now map this function over your hand by calling mapcar.
(defun test (hand)
(print (mapcar (lambda (lst)
(cond ((equal (first lst) 'J)
(cons '11 (cdr lst)))
((equal (first lst) 'Q)
(cons '12 (cdr lst)))
((equal (first lst) 'K)
(cons '13 (cdr lst)))
((equal (first lst) 'A)
(cons '14 (cdr lst)))
(t lst)))
hand)))
This no longer causes visible side-effects to your argument.
CL-USER> (defun test (hand)
(print (mapcar (lambda (lst)
(cond ((equal (first lst) 'J)
(cons '11 (cdr lst)))
((equal (first lst) 'Q)
(cons '12 (cdr lst)))
((equal (first lst) 'K)
(cons '13 (cdr lst)))
((equal (first lst) 'A)
(cons '14 (cdr lst)))
(t lst)))
hand)))
STYLE-WARNING: redefining COMMON-LISP-USER::TEST in DEFUN
TEST
CL-USER> (defparameter *a-hand* '((Q H)(A D)(J C)(Q S)(3 S)))
*A-HAND*
CL-USER> (test *a-hand*)
((12 H) (12 D) (12 C) (12 S) (12 S))
((12 H) (12 D) (12 C) (12 S) (12 S))
CL-USER> *a-hand*
((Q H) (A D) (J C) (Q S) (3 S))
CL-USER>
You're printing your output (along with some It's ogre now lines in the original) instead of merely returning it. As you can see in the REPL, this'll cause multiple copies to be displayed, and if you want to compose your test function later, the print won't really do anything for you. If you need to print the output, it's probably a better idea to leave that piece of logic up to the caller and merely focus on doing the replacement in the function itself.
(defun test (hand)
(mapcar (lambda (lst)
(cond ((equal (first lst) 'J)
(cons '11 (cdr lst)))
((equal (first lst) 'Q)
(cons '12 (cdr lst)))
((equal (first lst) 'K)
(cons '13 (cdr lst)))
((equal (first lst) 'A)
(cons '14 (cdr lst)))
(t lst)))
hand))
We've still got some repetition happening in that lambda form we're passing to mapcar. In particular, each clause involves consing a new value onto the cdr (or synonymously rest) of the input. Since the flow-control structures in Common Lisp are also functions that return values, we can compose them a little less repetitively.
(defun test (hand)
(mapcar (lambda (lst)
(cons
(cond ((equal (first lst) 'J) '11)
((equal (first lst) 'Q) '12)
((equal (first lst) 'K) '13)
((equal (first lst) 'A) '14)
(t (car lst)))
(cdr lst)))
hand))
cond probably isn't the best thing to use here in the first place. Since we're always doing the same check, and that check happens to be equality, we can instead use case.
(defun test (hand)
(mapcar (lambda (lst)
(cons
(case (first lst)
(J '11)
(Q '12)
(K '13)
(A '14)
(t (first lst)))
(cdr lst)))
hand))
Alternately, you could define a table of values, and look up the first element in it.
(defun test (hand)
(let ((table '(J 11 Q 12 K 13 A 14)))
(mapcar
(lambda (lst)
(cons (or (getf table (car lst)) (car lst))
(cdr lst)))
hand)))
Finally, you don't need to quote numbers Common Lisp. They're already self-evaluating.
(defun test (hand)
(mapcar (lambda (lst)
(cons
(case (first lst)
(J 11)
(Q 12)
(K 13)
(A 14)
(t (first lst)))
(cdr lst)))
hand))
If you're just getting started with programming, I'd recommend you go through these fantastic tutorials for Racket, rather than diving into Common Lisp right away.

Related

Lisp tree insertion

I made a lisp code that transforms a list of numbers into a tree. The rules of the tree are that the value of the left child node should always be smaller than the value of its parent node and the value of the right child node should always be higher than the value of its parent node.
Here is my lisp code:
(defun trees (list node)
(if (null list)
(list node)
(progn
(setf valueNode (car node))
(setf valueList (car list))
(if (< valueNode valueList)
(setf list (append (list (car list))
(cons (trees (car (cdr list)) node)
(car (cdr (cdr list)))))))
(if (> valueNode valueList)
(setf list (append (list (car list))
(cons (car (cdr list))
(trees (car (cdr (cdr list))) node))))))))
Normally,
This command
(write (trees '(8 (7 () ()) (12 () ())) '(10 () ())))
should return
(8 (7 () ()) (12 (10 () ()) ()))
but it actually returns (8 (7 () ())).
Also, if you need more explication just tell me and i'll clarify it.
(pls help me i'm very lost)
You are modifying list but not returning it.
Here is what you need to do:
(defun trees (list node)
(if (null list)
(list node)
(let ((valueNode (car node)) (valueList (car list)))
(if (< valueNode valueList)
(setf list (append (list (car list))
(cons (trees (car (cdr list)) node)
(car (cdr (cdr list)))))))
(if (> valueNode valueList)
(setf list (append (list (car list))
(cons (car (cdr list))
(trees (car (cdr (cdr list))) node)))))
list)))
now:
(trees '(8 (7 () ()) (12 () ())) '(10 () ()))
==> (8 (7 NIL NIL) 12 ((10 NIL NIL)))
PS. Please note the use of let and the correct indentation.

How would I write a function in Racket which produces true if all the numbers in a list are the same and false otherwise?

How would I define a function in Dr. Racket which produces boolean true if all the numbers in a list are the same and false otherwise.
This is my code so far:
(define (same-numbers? lst)
(cond
[(empty? (rest lst)) (first lst)]
[else (equal? (first lst)(same-numbers? (rest lst)))]))
If I type in:
(same-numbers? (cons 5 (cons 5 (cons 5 empty))))
My desired output is true. However, instead, I get a false. How would I correct this?
As the comments point out, assuming the list contains only numbers the simplest approach is to do (apply = lst). If you want to implement this from scratch with explicit recursion, I suggest a different approach: if the list has more than one element, take the first element as reference and compare all the others against it, like this:
(define (same-numbers? lst)
(if (or (empty? lst) (empty? (rest lst))) ; trivial cases
#t
(let loop ((val (first lst)) ; take first element as reference
(lst (rest lst))) ; loop over the other elements
(or (empty? lst) ; base case: we're finished
(and (equal? (first lst) val) ; base case: stop if elements are different
(loop val (rest lst))))))) ; recursive case: keep iterating
It works for my test cases:
(same-numbers? '())
=> #t
(same-numbers? '(5))
=> #t
(same-numbers? '(5 5))
=> #t
(same-numbers? '(5 5 5))
=> #t
(same-numbers? '(5 1))
=> #f
(same-numbers? '(1 5))
=> #f
(same-numbers? '(1 5 5))
=> #f
(same-numbers? '(5 5 1))
=> #f
I'll start with your code so far, and find the problems with it:
(define (same-numbers? lst)
(cond
[(empty? (rest lst)) (first lst)]
[else (equal? (first lst)(same-numbers? (rest lst)))]))
The first problem I see is with the base case: if lst is a list of numbers then (first lst) will be a number, not a boolean like you wanted.
;; same-numbers? : [Listof Number] -> Boolean
To fix this, the base case should return #true:
(define (same-numbers? lst)
(cond
[(empty? (rest lst)) #true]
[else (equal? (first lst) (same-numbers? (rest lst)))]))
The next problem I see is with the recursive case: since same-numbers? returns a boolean, you shouldn't use equal? as if you're expecting a number. Instead use equal? between the first and the second:
(define (same-numbers? lst)
(cond
[(empty? (rest lst)) #true]
[else ... (equal? (first lst) (second lst)) ... (same-numbers? (rest lst)) ...]))
Now the ...s around that need to be filled with stuff that combines the information in "first two equal" and "rest same-numbers". They're all equal when the first two are equal AND the rest are the same, so fill in the ...s with and to combine them:
(define (same-numbers? lst)
(cond
[(empty? (rest lst)) #true]
[else (and (equal? (first lst) (second lst)) (same-numbers? (rest lst)))]))
If I type in:
> (same-numbers? (cons 5 (cons 5 (cons 5 empty))))
#true
There's still one problem left: the empty list. So just add another cond case for it:
;; same-numbers? : [Listof Number] -> Boolean
(define (same-numbers? lst)
(cond
[(empty? lst) #true]
[(empty? (rest lst)) #true]
[else (and (equal? (first lst) (second lst)) (same-numbers? (rest lst)))]))
Using it:
> (same-numbers? empty)
#true
> (same-numbers? (cons 5 empty))
#true
> (same-numbers? (cons 5 (cons 5 (cons 5 empty))))
#true
> (same-numbers? (cons 5 (cons 5 (cons 6 empty))))
#false
Just like Atharva Shukla's comment (apply = lst) is good.
But (apply = '()) will show error.
#lang Racket
(define lon (list 1/2 1/2 1/2 1/3))
(define lon2 (list 1/2 1/2 1/2 0.5))
(define (same-n? lon)
(andmap (lambda (n) (= (first lon) n)) lon))
;;; TEST
(same-n? lon) ; #f
(same-n? lon2) ; #t
(same-n? '()) ; #t

How to remove a list of length 1 from a nested list in lisp?

I have a nested list (1 (4 (5) 3) 9 10) and I want to delete the lists of length 1 so the result would be (1 (4 3) 9 10).
This is what I have tried so far, which does not remove (5) and returns the original list.
(defun remove (l)
(cond
((null l) nil)
((and (listp (car l)) (= (length l) 1)) (remove (cdr l)))
((atom (car l)) (cons (car l) (remove (cdr l))))
(T (cons (remove (car l)) (remove (cdr l))))
))
Two things: first, remove is a predefined function in package CL, so I strongly advice to use a different name, let's say my-remove.
Second, you are testing the length of l instead of the sublist (car l), which is what you want to eliminate.
The correct form would be:
(defun my-remove (l)
(cond
((null l) nil)
((and (listp (car l)) (= (length (car l)) 1)) (my-remove (cdr l)))
((atom (car l)) (cons (car l) (my-remove (cdr l))))
(T (cons (my-remove (car l)) (my-remove (cdr l))))
))
Tail call recursive version. Plus: Without the test (atom (car l)) to be permissive for non-list and non-atom components in the list. (e.g. vectors or other objects as element of the list - they are treated like atoms.
(defun my-remove (l &optional (acc '()))
(cond ((null l) (nreverse acc))
((listp (car l)) (if (= 1 (length (car l))) ;; list objects
(my-remove (cdr l) acc) ;; - of length 1
(my-remove (cdr l) (cons (my-remove (car l)) acc)))) ;; - longer
(t (my-remove (cdr l) (cons (car l) acc))))) ;; non-list objects

Member function for nested list in Scheme

Can someone show me the error in this code please?
I want to generalize the member function to support nested lists. I need to search thing inside the nested list and return the rest of the list when I found thing. I don't really understand whats wrong with the code below.
(define (memberk thing lis)
(cond
((null? lis) #f)
((list? (car lis))
(cons (memberk thing (car lis))
(memberk thing (cdr lis))))
(else
(if (equal? (car lis) thing)
lis
(memberk thing (cdr lis))))))
Expexted output: (memberk 3 '(1 4 (3 1) 2)) = '((3 1) 2)
Actual output from the code above: '((3 1) . #f)
So how I see this you would like the top level cons that has the key found somewhere in car. I'm thinking something like:
(define (memberk needle lst)
(define (found? haystack)
(or (equal? needle haystack)
(and (pair? haystack)
(or (found? (car haystack))
(found? (cdr haystack))))))
(let loop ((lst lst))
(cond ((null? lst) #f)
((found? (car lst)) lst)
(else (loop (cdr lst))))))
(memberk '(a) '(a b (b (a) c) c d)) ; ==> ((b (a) c) c d)
Something like this?
It is a bit unclear what you want - since there is only one test case.
(define (memberk thing lis)
(cond
[(null? lis)
#f]
[(and (cons? (car lis)) (memberk thing (car lis)))
=> (λ (found) (cons found (cdr lis)))]
[(equal? (car lis) thing)
lis]
[else
(memberk thing (cdr lis))]))

Weird syntax in common lisp

I found this lisp function while I was googling
(defun filter (lst items-to-filter)
(cond ((null lst) nil)
((member (car lst) items-to-filter) #1=(filter (cdr lst) items-to-filter))
(t (cons (car lst) #1#))))
It's just set difference, but this is the first time i see #1= and #1#, syntax. I think I understand what it means just by looking at the code, but I am not too sure. I think the #1= is used to label an expression so as not to retype it later when needed, one can just refer to it by #index#, in this case index=1. I was wondering if someone could shed some light on this. What are these constructs called, if there's a reference for them, and if they are widely used in modern lisp code. Thanks
To see it in written source code is very very unusual. Most of the time you see it in data. It is used to create or print shared data items in s-expressions. This way you can also read or print circular s-expressions.
You could use it for easier creation of repeated code, but usually one writes functions or macros for that. Functions have the advantage that they save code space - unless they are inlined.
CL-USER 3 > (pprint '(defun filter (lst items-to-filter)
(cond ((null lst) nil)
((member (car lst) items-to-filter)
#1=(filter (cdr lst) items-to-filter))
(t (cons (car lst) #1#)))))
(DEFUN FILTER (LST ITEMS-TO-FILTER)
(COND ((NULL LST) NIL)
((MEMBER (CAR LST) ITEMS-TO-FILTER)
(FILTER (CDR LST) ITEMS-TO-FILTER))
(T
(CONS (CAR LST) (FILTER (CDR LST) ITEMS-TO-FILTER)))))
As you see above the printer does not print it that way. Why is that?
There is a global variable *print-circle* which controls it. For above example it was set to NIL. Let's change that:
CL-USER 4 > (setf *print-circle* t)
T
CL-USER 5 > (pprint '(defun filter (lst items-to-filter)
(cond ((null lst) nil)
((member (car lst) items-to-filter)
#1=(filter (cdr lst) items-to-filter))
(t (cons (car lst) #1#)))))
(DEFUN FILTER (LST ITEMS-TO-FILTER)
(COND ((NULL LST) NIL)
((MEMBER (CAR LST) ITEMS-TO-FILTER)
#1=(FILTER (CDR LST) ITEMS-TO-FILTER))
(T
(CONS (CAR LST) #1#))))
So this shows that one can read and print such s-expressions in Common Lisp
Sharing some source code data structures is more common in computed code:
CL-USER 22 > (defmacro add-1-2-3 (n) `(,n 1 2 3))
ADD-1-2-3
CL-USER 23 > (walker:walk-form '(+ (add-1-2-3 4) (add-1-2-3 5)))
(+ (4 . #1=(1 2 3)) (5 . #1#))

Resources