i have a simple boolean expression presented as a lisp list like this :
'(OR 0 (AND A1 A2))
the previous list is the presentation of ((A1 AND A2)OR 0).
anyway , i am writing a function to simplify this expression ..
for example :
calling the function "reduce" like this :
(reduce '(OR 0 (AND A1 A2)))
would yield
(AND A1 A2)
i firstly tried to create base rules , so i defined
the following identities:
(AND 1 S) == S,
(OR 0 S ) == S,
(AND 0 S) == 0,
( OR 1 S) == 1,
(NOT O) == 1,
(NOT 1) == 0.*
i was thinking of defining 6 functions , one for each rule , and then
call them one by one in a wrapper , i am new to lisp so i don't have a clue to implement that , i made it in java once , but i dont know how to handle such problem using the syntax of lisp so please help me ..
Given the complexity of your solution, here's my implementation that's a lot shorter and more readable:
(defun reduc (exp)
(if (atom exp)
exp
(flet ((helper (op args n) ; and and or is nearly the same code so we factor it out
(let ((newargs (remove n args)) (cn (- 1 n)))
(cond
((null newargs) n)
((some (lambda (e) (eql cn e)) newargs) cn)
((null (cdr newargs)) (car newargs))
((cons op newargs))))))
(let ((op (car exp)) (args (mapcar #'reduc (cdr exp))))
(ecase op
((not) (if (= 1 (length args))
(let ((arg1 (car args)))
(if (and (numberp arg1) (<= 0 arg1 1)) (- 1 arg1) exp))
(error "'not' must have exactly one parameter")))
((and) (helper op args 1))
((or) (helper op args 0)))))))
Testing:
? (reduc '(OR 0 (AND A1 A2)))
(AND A1 A2)
? (reduc '(OR 0 (AND A1 1 A2)))
(AND A1 A2)
? (reduc '(or ERROR (not 0)))
1
? (reduc '(AND ERROR (not 0)))
ERROR
? (reduc '(OR 0 (AND A1 0)))
0
? (reduc '(OR 0 (AND A1 1)))
A1
i finally came up with this solution .
(defun simplify (EXPR)
(simplify-expr NIL EXPR))
(defun simplify-expr (EXPR1 EXPR2)
(cond
((or (atom EXPR2) (equal EXPR1 EXPR2)) EXPR2)
(T (simplify-expr EXPR2 (simplify-boolean-expr EXPR2)))))
(defun simplify-boolean-expr (EXPR)
(cond
((and (equal (first EXPR) `and) (>= (length EXPR) 3))
(simplify-and-expr (rest EXPR)))
((and (equal (first EXPR) `or) (>= (length EXPR) 3))
(simplify-or-expr (rest EXPR)))
((and (equal (first EXPR) `not) (= (length EXPR) 2))
(simplify-not-expr (rest EXPR)))
(T
(error "~S is not a valid circuit descriptor expression or has an unknown operator." EXPR))))
(defun simplify-and-expr (EXPR)
(let ((SIMPLIFIED_EXPR (remove `T (remove-duplicates EXPR))))
(cond
((null SIMPLIFIED_EXPR) `T)
((member `NIL SIMPLIFIED_EXPR) `NIL)
((null (second SIMPLIFIED_EXPR)) (first SIMPLIFIED_EXPR))
(T (cons `and (simplify-operand SIMPLIFIED_EXPR))))))
(defun simplify-or-expr (EXPR)
(let ((SIMPLIFIED_EXPR (remove `NIL (remove-duplicates EXPR))))
(cond
((null SIMPLIFIED_EXPR) `NIL)
((member `T SIMPLIFIED_EXPR) `T)
((null (second SIMPLIFIED_EXPR)) (first SIMPLIFIED_EXPR))
(T (cons `or (simplify-operand SIMPLIFIED_EXPR))))))
(defun simplify-not-expr (EXPR)
(cond
((equal (first EXPR) `NIL) `T)
((equal (first EXPR) `T) `NIL)
((and (listp (first EXPR)) (equal (first (first EXPR)) `not))
(first (rest (first EXPR))))
(T (cons `not (simplify-operand EXPR)))))
(defun simplify-operand (OPERAND_LIST)
(cond
((null OPERAND_LIST) NIL)
((atom (first OPERAND_LIST))
(cons (first OPERAND_LIST) (simplify-operand (rest OPERAND_LIST))))
(T
(cons (simplify-expr NIL (first OPERAND_LIST)) (simplify-operand (rest OPERAND_LIST))))))
it takes (nil , T) for (0 , 1) and reduces any boolean expression , i tried it and it works fine .
Related
I'm new to lisp, and am writing code for quicksort. I am almost done, although the output is giving me some trouble. This is currently what I have:
(defun fil(P L)
(if (null L) nil
(if (funcall P (first L)) (cons (first L) (fil P (rest L)))
(fil P (rest L)))))
(defun qs(L)
(if (null L) nil
(let ((x (first L))
(gt (fil (lambda (x) (<= (first L) x))(rest L) ))
(lt (fil (lambda (x) (> (first L) x))(rest L))))
(cons (cons (qs lt) (first L)) (qs gt)))))
(write (qs '(4 2 3 1 7 3 5 3 6)))
This works, but the output looks like this:
((((((NIL . 1)) . 2) (NIL . 3) (NIL . 3) (NIL . 3)) . 4)
(((NIL . 5) (NIL . 6)) . 7))
I am not sure where the extra nils and periods and parentheses are coming from or how to fix it. Any advice is appreciated.
Look at
(cons '(a b c d) 'e)
Above code does not append E to the list.
CL-USER 4 > (cons '(a b c d) 'e)
((A B C D) . E)
It creates a new cons cell (a two element container) with the first arg and the second arg with its elements.
What you need, is to APPEND lists into a result list.
Adding to what #RainerJoswig said:
(defun %filter (pred l)
(cond ((null l) nil)
((funcall pred (car l)) (cons (car l) (%filter pred (cdr l))))
(t (%filter pred (cdr l)))))
(defun quicksort (l)
(cond ((null l) nil)
(t (let ((greater-than (%filter (lambda (x) (<= (car l) x)) (cdr l)))
(less-than (%filter (lambda (x) (> (car l) x)) (cdr l))))
(append (quicksort less-than) (list (car l)) (quicksort greater-than))))))
(quicksort '(4 2 3 1 7 3 5 3 6))
;; (1 2 3 3 3 4 5 6 7)
Alternatively also:
(defun %filter (pred l)
(mapcan (lambda (x) (if (funcall pred x) (list x) nil)) l))
(defun quicksort (l)
(cond ((null l) nil)
(t (append (quicksort (%filter (lambda (x) (< x (car l))) (cdr l)))
(list (car l))
(quicksort (%filter (lambda (x) (<= (car l) x)) (cdr l)))))))
I am trying to check if a list has a mountain aspect or not in lisp.
e.g:1,5,9,6,4,3
l is my list and aux is 0-the ascending part of l or 1-the descending part of the list.
muntemain just call munte starting with aux=0,the ascending part
my error is :
Badly formed lambda: (AND (< (CAR L) (CAR (CDR L))) (EQ AUX 0))
and I can't see the problem.Can someone help please?
(defun munte (l aux)
(cond
((and (atom l) (null aux)) NIL)
((and (null l) (null aux)) NIL)
((and (atom l) (eq aux 1)) T)
((and (null l) (eq aux 1) T)
((and (< (car l) (car(cdr l))) (eq aux 0)) (munte(cdr l) 0))
((and (or (> (car l) (cadr l)) (= (car l) (cadr l))) (eq aux 0))(munte(cdr l) 1))
( and (> (car l) (cadr l)) (eq aux 1)) (munte(cdr l) 1))
(T NIL)
)
)
(defun muntemain (l)
(cond
((> (car l) (cadr l)) NIL)
((< (length l) 2) NIL)
(T (munte l 0))
)
)
Formatting
As noted by Barmar, you really need to use an editor to help you with the parenthesis. There are many tutorials for installing Emacs+Slime. Take some time to install proper tools.
Don't use EQ for numbers and characters
An implementation is permitted to make "copies" of characters and
numbers at any time. The effect is that Common Lisp makes no guarantee
that eq is true even when both its arguments are "the same thing" if
that thing is a character or number.
Factorize tests
((and (atom l) (null aux)) NIL)
((and (null l) (null aux)) NIL)
((and (atom l) (eq aux 1)) T)
((and (null l) (eq aux 1) T)
From the definition of atom, NIL is an atom, so you don't need (null L). The different cases for aux can be grouped too. The clause below is sufficient to account for all the above ones:
((atom L) (eql aux 1))
But I don't understand why aux is not a boolean in the first place if you always bind it to 0 or 1. Just use t and nil and return aux in the above clause.
Use meaningful functions
(< (car l) (car(cdr l)))
Of course, (car(cdr ..)) is known as (cadr ..), but also as second. The above test is equivalent to:
(< (first L) (second L))
And what if your list has no second element? You will compare a number against nil and signal an error (not what you want). You need more tests. In muntemain, you seem to have a special case for when length is below 2, but the test is done only if the previous returns nil, which won't happen if an error is signaled.
An iterative alternative
Here is a completely different way to attack the problem, just to give you ideas.
(lambda (list)
(loop
;; memories
for px = nil then x
for pdx = nil then dx
;; current element
for x in list
;; first and second "derivatives" (signs only)
for dx = 1 then (signum (- x px))
for ddx = 0 then (signum (- dx pdx))
;; checks
sum ddx into total
always (and (<= dx 0) (<= -1 total 0))
finally (return (= total -1))))
This is my function that's supposed to implement infix evaluation for * and + operations.
(defun calculate(l)
(cond
((eql (cadr l) '+) (+ (car l) (cddr l)))
((eql (cadr l) '*) (- (car l) (cddr l)))
)
)
When I run this with the list '(3 + 4) it gives me an error saying "(4) is not a number". Any ideas what the problem might be?
Symbols can be called as functions. Thus your code is just this:
(defun calculate (l)
(funcall (second l) (first l) (third l)))
or
(defun calculate (l)
(destructuring-bind (arg1 op arg2)
l
(funcall op arg1 arg2)))
Example:
CL-USER 77 > (calculate '(20 + 30))
50
The part with (cddr l) should be (caddr l). You have to access the first element of the list, not the list. The code should be then:
(defun calculate(l)
(cond
((eql (cadr l) '+) (+ (car l) (caddr l)))
((eql (cadr l) '*) (- (car l) (caddr l)))
)
)
I am trying to do a quicksort using LISP but I am having trouble with my functions output.
(defun qsort (L)
(cond
((null L) nil)
(t(append
(qsort (list< (car L) (cdr L)))
(cons (car L) nil)
(qsort (list>= (car L) (cdr L)))))))
(defun list< (a b)
(cond
(( or(null a)(null b) nil))
(( < a (car b)) (list< a (cdr b)))
(t(cons (car b) (list< a (cdr b))))))
(defun list>= (a b)
(cond
(( or( null a)(null b) nil))
(( >= a (car b)) (list> a (cdr b)))
(t(cons (car b) (list> a (cdr b))))))
My problem being when list< and list>= finish the list always ends with a .T. For instance:
> (list< '4 '(1 5 3 8 2))
Entering: LIST<, Argument list: (4 (1 5 3 8 2))
Entering: LIST<, Argument list: (4 (5 3 8 2))
Entering: LIST<, Argument list: (4 (3 8 2))
Entering: LIST<, Argument list: (4 (8 2))
Entering: LIST<, Argument list: (4 (2))
Entering: LIST<, Argument list: (4 NIL)
Exiting: LIST<, Value: T
Exiting: LIST<, Value: (2 . T)
Exiting: LIST<, Value: (2 . T)
Exiting: LIST<, Value: (3 2 . T)
Exiting: LIST<, Value: (3 2 . T)
Exiting: LIST<, Value: (1 3 2 . T)
(1 3 2 . T)
Why is (4 NIL) evaluating as T?
Your problem with list<, and also with list>=, lies on ((or ( null a)(null b) nil)), it should be (( or( null a)(null b)) nil). Note nil was moved outside of the condition to be the returned value.
Furthermore, on the definition of list>= you are calling list>, but I'm positive you meant list>= instead.
I would also suggest some indentation to address the legibility of lisp, like follows
(defun qsort (L)
(cond
((null L) nil)
(t
(append
(qsort (list< (car L) (cdr L)))
(cons (car L) nil)
(qsort (list>= (car L) (cdr L)))))))
(defun list< (a b)
(cond
((or (null a) (null b)) nil)
((< a (car b)) (list< a (cdr b)))
(t (cons (car b) (list< a (cdr b))))))
(defun list>= (a b)
(cond
((or (null a) (null b)) nil)
((>= a (car b)) (list>= a (cdr b)))
(t (cons (car b) (list>= a (cdr b))))))
Some testing follows:
(list< '4 '(1 5 3 8 2))
=> (1 3 2)
(list>= '4 '(1 5 3 8 2))
=> (5 8)
(qsort '(1 5 3 8 2))
=> (1 2 3 5 8)
Lisp has different kinds of collections. I think sort a list using quick-sort is not a good choice. In the implementation of STL in C++, the sorting method of list is merge-sort. I have tried to implement a 3-way quick-sort using the collections of array.
(defun quick-sort (arr start end)
"Quick sort body"
(if (< start end)
(let ((n-pair (partition arr start end)))
(quick-sort arr start (car n-pair))
(quick-sort arr (cdr n-pair) end))
))
(defun partition (arr start end)
"Partition according to pivot."
(let ((pivot (aref arr start)) (cur start))
(loop while (<= start end) do
(cond
((< pivot (aref arr start)) ; pivot < arr[start], swap with arr[end]
(swap arr start end) (decf end))
((> pivot (aref arr start)) ; pivot > arr[start], swap with arr[start]
(swap arr cur start) (incf cur) (incf start))
(t ; otherwise
(incf start))))
(cons (decf cur) start)))
(defun swap (arr i j)
"Swap element of arr"
(let ((tmp (aref arr i)))
(setf (aref arr i) (aref arr j))
(setf (aref arr j) tmp)))
(defun quick (list)
(when (< = (length list) 1) (return-from quick list))
(let ((pivot (car list)) (rest (cdr list)) (less nil) (greater nil))
(loop for i in rest do
(if (< i pivot) (push i less) (push i greater)))
(append (quick less) (list pivot) (quick greater))))
I'd recommend to change the code of liya babu/Will Ness like this:
(defun quick (list)
(if (null list) nil
(let ((pivot (first list)) (less nil) (greater nil))
(dolist (i (rest list))
(if (< i pivot) (push i less) (push i greater)))
(append (quick less) (list pivot) (quick greater)))))
Although just slightly edited I find it both more lispy and more succinct.
There are some errors in the program. The corrected program is:
(defun qsort (L)
(cond
((null L) nil)
(t (append
(qsort (list< (car L) (cdr L)))
(cons (car L) nil)
(qsort (list>= (car L) (cdr L)))))))
(defun list< (a b)
(cond
(( or (null a) (null b)) nil)
(( < a (car b)) (list< a (cdr b)))
(t (cons (car b) (list< a (cdr b))))))
(defun list>= (a b)
(cond
(( or ( null a)(null b)) nil)
(( >= a (car b)) (list>= a (cdr b)))
(t (cons (car b) (list>= a (cdr b))))))
This should also work:
(defun qsort (l)
(cond
((null l) nil)
(t (append
(qsort (car(list<> (car l)(cdr l))))
(cons (car l) nil)
(qsort (cadr(list<> (car l)(cdr l))))))))
(defun list<> (a b &optional rl rr)
(cond
((null b) (list rl rr))
((<=(car b)a) (list<> a (cdr b) (cons (car b) rl) rr))
(t (list<> a (cdr b)rl (cons (car b) rr)))))
(setq l (loop for j from 1 to 20 append (list(random 100))))
(qsort l)
;=> (86 99 9 31 66 58 57 43 48 21 51 0 32 69 39 47 59 76 69 23)
;=> (0 9 21 23 31 32 39 43 47 48 51 57 58 59 66 69 69 76 86 99)
Need to write a union function in lisp that takes two lists as arguments and returns a list that is the union of the two with no repeats. Order should be consistent with those of the input lists
For example: if inputs are '(a b c) and '(e c d) the result should be '(a b c e d)
Here is what I have so far
(defun stable-union (x y)
(cond
((null x) y)
((null y) x))
(do ((i y (cdr i))
(lst3 x (append lst3
(cond
((listp i)
((null (member (car i) lst3)) (cons (car i) nil) nil))
(t (null (member i lst3)) (cons i nil) nil)))))
((null (cdr i)) lst3)))
My error is that there is an "illegal function object" with the segment (null (member (car i) lst3))
Advice?
You've got your parens all jumbled-up:
(defun stable-union (x y)
(cond
((null x) y)
((null y) x) ) END OF COND form - has no effect
(do ((i y (cdr i))
^^
(lst3 x (append lst3
(cond
((listp i)
( (null (member (car i) lst3))
^^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ called as a function
(cons (car i) nil) with two arguments
nil ) )
^^
(t NEXT 3 forms have no effect
(null (member i lst3))
(cons i nil)
nil )))) )
^^
((null (cdr i)) lst3)))
Here's your code as you probably intended it to be, with corrected parenthesization and some ifs added where needed:
(defun stable-union (x y)
(cond
((null x) y)
((null y) x)
(t
(do ((i y (cdr i))
(lst3 x (append lst3
(cond
((listp i)
(if (null (member (car i) lst3))
(cons (car i) nil)
nil))
(t
(if (null (member i lst3))
(cons i nil)
nil))))))
((null (cdr i)) lst3)))))
There are still problems with this code. Your do logic is wrong, it skips the first element in y if it contains just one element. And you call append all the time whether it is needed or not. Note that calling (append lst3 nil) makes a copy of top-level cons cells in lst3, entirely superfluously.
Such long statements as you have there are usually placed in do body, not inside the update form for do's local variable.
But you can use more specialized forms of do, where appropriate. Here it is natural to use dolist. Following "wvxvw"'s lead on using hash-tables for membership testing, we write:
(defun stable-union (a b &aux (z (list nil)))
(let ((h (make-hash-table))
(p z))
(dolist (i a)
(unless (gethash i h)
(setf (cdr p) (list i) p (cdr p))
(setf (gethash i h) t)))
(dolist (i b (cdr z))
(unless (gethash i h)
(setf (cdr p) (list i) p (cdr p))
(setf (gethash i h) t)))))
using a technique which I call "head-sentinel" (z variable pre-initialized to a singleton list) allows for a great simplification of the code for the top-down list building at a cost of allocating one extra cons cell.
The error is because you're trying to execute the result of evaluating (null (member (car i) lst3)). In your cond expression, if i is a list, then it attempts to evaluate the expression
((null (member (car i) lst3)) (cons (car i) nil) nil))
And return the result. The first element in an expression should be a function, but
(null (member (car i) lst3))
Is going to return a boolean value. Hence the failure. The structure of your code needs some attention. What you've missed is that you need an inner cond, there.
Incidentally, this would be a much cleaner function if you did it recursively.
I'm a Schemer rather than a Lisper, but I had a little think about it. Here's the skeleton of a recursive implementation:
(defun stable-union (x y)
(cond
((null x) y)
((null y) x)
((listp y)
(cond
((member (car y) x) (stable-union ??? (???)))
(t (stable-union (append x (??? (???))) (cdr y)))))
((not (member y x)) (append x (list y)))
(t x)))
(Edited to correct simple tyop in second-last line, thanks to Will Ness for spotting it)
(remove-duplicates (append '(a b c) '(e c d)) :from-end t)
Because you started off with do, and because a recursive solution would be even worse, here's what you could've done:
(defun union-stable (list-a list-b)
(do ((i list-b (cdr i))
filtered back-ref)
((null i) (append list-a back-ref))
(unless (member (car i) list-a)
(if back-ref
(setf (cdr filtered) (list (car i))
filtered (cdr filtered))
(setf back-ref (list (car i))
filtered back-ref)))))
This is still quadratic time, and the behaviour is such that if the first list has duplicates, or the second list has duplicates, which are not in the first list - they will stay. I'm not sure how fair it is to call this function a "union", but you'd have to define what to do with the lists if they have duplicates before you try to unify them.
And this is what you might've done if you were interested in the result, rather than just exercising. Note that it will ensure that elements are unique, even if the elements repeat in the input lists.
(defun union-stable-hash (list-a list-b)
(loop for c = (car (if list-a list-a list-b))
with back-ref
with hash = (make-hash-table)
for key = (gethash c hash)
with result
do (unless key
(if back-ref
(setf (cdr result) (list c)
result (cdr result))
(when (or list-a list-b)
(setf back-ref (list c)
result back-ref)))
(setf (gethash c hash) t))
do (if list-a (setf list-a (cdr list-a))
(setf list-b (cdr list-b)))
do (unless (or list-a list-b)
(return back-ref))))