(defun solve (L)
(cond
((null L) nil)
(t(eval (list (car (cdr L)) (car L) (car (cdr (cdr L))))))))
The code I have is a simple evaluate program that works fine as long as the input is something like '(5 + 4). However I want to be able to solve other inputs such as '(5 +( 3 - 1)) and '(6 + 5) - (4 /2 ). My problem obviously being how to handle the parentheses. I tried comparing the literal value of '( as in ((equal (car L) '( ) (solve(cdr L))) but that only throws all of my close parentheses out of whack. Is there a way to check if an atom is a parentheses?
I'm hoping that if this is a homework question, you look at Mars's comments instead of my answer. You're not going to do well if you just take my code. On the other hand, if you actually read through everything and really understand it, that's something.
Like Mars said, we need to recurse. It's simple enough; if we have a number, return it.
(defun solve (expression)
(if (atom expression)
expression
'havent-dealt-with-this-yet))
[22]> (solve '3)
3
If we've got a list, take the second thing, assume it's the operator, and eval it the way you did in our sample:
(defun solve (expression)
(if (atom expression)
expression
(eval (list (second expression)
(first expression)
(third expression)))))
[25]> (solve 3)
3
[26]> (solve '(3 + 4))
7
Cool. But here we're no further than your original code. What happens if we have a nested expression?
[27]> (solve '(3 + (2 * 2)))
*** - EVAL: 2 is not a function name; try using a symbol instead
Well, this isn't working. We can't just assume that either of (first expression) or(third expression)` are values; they may be expressions themselves. But we need to figure out the value of the expression. Let's assume we have a way to take an expression and find its value. Then our code can be:
(defun solve (expression)
(if (atom expression)
expression
(eval (list (second expression)
(find-expression-value (first expression))
(find-expression-value (third expression))))))
Wait! solve is a function that takes an expression and finds its value!
(defun solve (expression)
(if (atom expression)
expression
(eval (list (second expression)
(solve (first expression))
(solve (third expression))))))
[43]> (solve 3)
3
[44]> (solve '(3 + 2))
5
[45]> (solve '((3 + 1) * (6 / 2)))
12
ta-da!
Related
I'm learning Lisp now, and I'm trying to do an exercise that asks me to get the maximum value of a list, the syntax is totally different from most programming languages I've learned, so I'm having some difficulties.
My code:
(defun test(y)
(cond
((and (first y) (> (second y)) (> (third y)))
(format t "numero maximo ~d" (first y))
((and (second y) (> (first y)) (> (third y)))
(t (format t "numero maximo ~d" (second y))
((and (third y) (> (second y)) (> (first y)))
(t (format t "numero maximo ~d" (third y))
))
I'm receiving this error: incomplete s-expression in region
Your code is too complex, it tries to take elements from a list, compare them, and print something. Like in other languages, use smaller functions and, particularly with a new language, test often in order to avoid having to debug something too large.
Your code, automatically indented with Emacs, looks as follows:
(defun test(y)
(cond
((and (first y) (> (second y)) (> (third y)))
(format t "numero maximo ~d" (first y))
((and (second y) (> (first y)) (> (third y)))
(t (format t "numero maximo ~d" (second y))
((and (third y) (> (second y)) (> (first y)))
(t (format t "numero maximo ~d" (third y))
))
And the editor complains about unbalanced parentheses:
In (> (second y)), the > function is given only one argument
All your cond clauses are in fact nested inside the first clause. Using an editor that highlights matching parentheses helps a lot here. The syntax should be:
(cond
(test-1 ...)
(test-2 ...)
(t ...))
If your test involves calling predicates, then it looks like:
(cond
((and (f1 ...) (f2 ...)) ;; <-- test
... ;; <-- code
) ;; end of first clause
) ;; end of cond
But note that you do not need to put comments for closing delimiters, the indentation and the automatic highlighting of parentheses should help you avoid mistakes.
Let's try a rewrite.
First of all, you can write a function that just compares numbers, not thinking about lists or formatting; here is a very straightforward max-of-3 implementation (without cheating and calling the built-in max function):
(defun max-of-3 (x y z)
(if (> x y)
(if (> x z) x z)
(if (> y z) y z)))
Evaluate the function, and test it on multiple inputs, for example in the REPL:
CL-USER> (max-of-3 0 2 1)
2
....
Then, you can build up the other function, for your list:
(defun test (list)
(format t
"numero maximo ~d"
(max-of-3 (first list)
(second list)
(third list))))
If you need to do more error checking ahead of time, like checking that the lists is well-formed, you should probably define other auxiliary functions.
If I understood the question and answer, I might be able to provide a solution or two that returns the max, regardless of the length of the list. So, these solutions are not limited to a list of three.
This illustrates a way to test where "max-lst" is the Lisp function under test:
(defconstant test-case
(list 1 2 0 8 7 6 9 4 5))
(defun run-test ()
(max-lst test-case))
Solution 1
This solution uses recursion. If you like loops better, Lisp has several loops. The Lisp function "max" is not used:
(defun max-lst (lst-in)
(cond ((null (second lst-in))
(first lst-in))
((> (first lst-in) (second lst-in))
(max-lst
(list* (first lst-in) (rest (rest lst-in)))))
(t
(max-lst
(list* (rest lst-in))))))
Solution 2
If you have no objection to using the Lisp function "max," here is a solution using max.
Note that max is not limited to two arguments.
(max 5 6 4 7 3)
will return 7.
In this solution, the function "max" is passed to the function "reduce" as an argument. The "reduce" function takes a function and a list as arguments. The function is applied to each adjacent pair of arguments and returns the result. If you want the sum, you can pass the + argument.
(defun max-lst-using-max (lst-in)
(reduce #'max lst-in))
Alas, I fear that I provide these solutions too late to be pertinent to the original poster. But maybe someone else will have a similar question. So, perhaps this could help, after all.
I'm a newbie when it comes to programming in lisp and ill be honest recursion is not my forte, I was tasked with writing a function that would simplify arithmetic equations but not solve them. Here is the guidelines this is a school project by the way.
*Write function simplify that takes any arithmetic expression as described above (not just the examples shown) and returns a new function in which the following improvements are made, if they are possible:
Multiplication sub-expression
a. With a 0 as an argument, sub-expression is replaced by 0: (* 3 5 0) -> 0
b. With a 1 as an argument, the 1 is removed: (* 1 2 6) -> (* 2 6). If only one argument remains then the sub-expression is replaced by that argument: (* 1 6) -> 6
Addition sub-expression
a. Any occurrence of 0 is eliminated: (+ 0 2 7 7) -> (+ 2 7 7). If only one argument remains, the sub-expression is eliminated: (+ 0 7) -> 7
My group mates and I have written this so far :
(defun simplify (lis)
(cond
((null lis) '())
((eq (car lis) '*)
(cond
((not(null (member '0 lis))) 0)
((not(null (member '1 lis))) (simplify (remove '1 lis)))
(t (simplify (cdr lis)))
)
)
((eq (car lis) '+)
(cond
(t 0)
)
)
((listp (car lis)) (cons (simplify (car lis))(simplify (cdr lis))))
(t (cons (simplify (car lis)) (simplify (cdr lis))))
)
)
We cant get it to work Correctly if you have any suggestions! Thank you also you can ignore our + function that isn't finished.
It's always good to try to keep functions as simple and short as possible. So let's break up this task into multiple steps:
For both + and * there is an identity element, that you are supposed to remove from the operation (as it doesn't affect the result).
(defun remove-identity-elements (operands identity)
(flet ((is-identity (element)
(equal element identity)))
(let ((filtered-operands (remove-if #'is-identity operands)))
(or filtered-operands (list identity)))))
This function returns a list of operands with identity elements removed. Note that I added a check to avoid returning an empty list, so if the filtered-operands are an empty list (()) the or will evaluate its second argument, returning a list with the identity element as single member.
For an operation, if it's called with only a single operand, you're supposed to simplify that to only the single operand. That task is a good candidate for another function:
(defun compact-single-operand-operation (expression)
(let ((operands (rest expression)))
(if (rest operands)
expression
(first operands))))
Handling an operation can then be done by first removing any identity elements from the operands and then eventually removing the operation all together:
(defun simplify-operation (operator operands identity)
(compact-single-operand-operation
(cons operator (remove-identity-elements operands identity))))
With these functions ready at hand we can approach the simplify function. First of all, we need to cover its recursive nature:
In order to simplify an operation, you need to first simplify each of its operands, as they could be complex (simplify-able) operations, too.
(defun simplify (expression)
(if (listp expression)
(let ((operator (first expression))
(operands (mapcar #'simplify (rest expression))))
;; handle operations
)
expression))
I'm using mapcar with the currently being defined function simplify to get already simplified operands. To stop this recursion we need a base case: If the expression to simplify isn't a list, then we consider it as "self evaluating" and just return it unchanged (this is the "else" part of the if).
Handling the operations is done using the above function simplify-operation, though we need to add a special check to cope with a possible 0 in the operands of a multiplication:
(cond ((eq operator '+) (simplify-operation '+ operands 0))
((eq operator '*)
(if (find 0 operands)
0
(simplify-operation '* operands 1)))
(t (error "Unsupported operation")))
I also put together a live example to play with.
I have a function that replaces all instances of a symbol in a list:
(defun replace-symbol-in-sexp-fn (symbol-to-replace new-symbol sexp)
(if (eq sexp nil)
sexp
(cons
(if (listp (car sexp))
(replace-symbol-in-sexp-fn symbol-to-replace new-symbol (car sexp))
(if (eq (car sexp) symbol-to-replace)
(setf (car sexp) new-symbol)
(car sexp)))
(replace-symbol-in-sexp-fn symbol-to-replace new-symbol (cdr sexp)))))
(defmacro replace-symbol-in-sexp (symbol-to-replace new-symbol sexp)
`(replace-symbol-in-sexp-fn ,symbol-to-replace ,new-symbol ,sexp))
(macroexpand-1 (replace-symbol-in-sexp '+ '* (+ 2 3)))
; => TYPE-ERROR "The value 5 is not of type LIST" if sexp has comma,
; => UNBOUND-VARIABLE "The variable SEXP is unbound" if sexp has no comma
I'm getting either a type error or an undefined-variable error when attempting to evaluate the final expression, depending upon whether sexp is comma'd or not in the last line. I've tested and replace-symbol-in-sexp-fn works when given, say:
(replace-symbol-in-sexp-fn '+ '* '(+ 2 3)) ; => (* 2 3)
I'm trying to now produce this with a macro so that the sexp doesn't have to be quoted like '(+ 2 3), and so I can run replace-symbol-in-sexp-fn with arbitrary lisp code. Obviously, I could eval and pass in a sexp quoted to replace-symbol-in-sexp-fn, like:
(eval (replace-symbol-in-sexp-fn '+ '* '(+ 2 3))
But that's a clunky attempt to imitate macros, so I'd prefer to actually just use a macro. Is there a clean way to do what I'm trying to do with macros? What am I missing?
So you reimplemented the Common Lisp function nsubst. subst is the normal version and n indicates that it is the destructive version (non-consing).
Note that in portable Common Lisp it is not a good idea to modify literal data. The effects are undefined. Ignoring that for a while:
(macroexpand-1 (replace-symbol-in-sexp '+ '* (+ 2 3)))
But probably you wanted to macroexpand the expression and not the result? Probably should be:
(macroexpand-1 '(replace-symbol-in-sexp '+ '* (+ 2 3)))
But that macro makes no sense. The generated code is false, since the last argument does not evaluate to a list. The macro has to create useful code. As you see the last expression is unquoted, which make no sense.
CL-USER 14 > (macroexpand-1 '(replace-symbol-in-sexp '+ '* (+ 2 3)))
(REPLACE-SYMBOL-IN-SEXP-FN (QUOTE +) (QUOTE *) (+ 2 3))
Let's introduce a quote:
(defmacro replace-symbol-in-sexp (symbol-to-replace new-symbol sexp)
`(replace-symbol-in-sexp-fn ,symbol-to-replace ,new-symbol ',sexp))
CL-USER 17 > (macroexpand-1 '(replace-symbol-in-sexp '+ '* (+ 2 3)))
(REPLACE-SYMBOL-IN-SEXP-FN (QUOTE +) (QUOTE *) (QUOTE (+ 2 3)))
Is that macro useful? I have my doubts.
It seems that you do not want to expand to the function invocation, but use the function to expand your code. You should not quote it then:
(defmacro replace-symbol-in-sexp (symbol-to-replace new-symbol sexp)
(replace-symbol-in-sexp-fn symbol-to-replace new-symbol sexp))
I have the impression that you are just trying to re-implement something like symbol-macrolet.
I'm having issues trying to form code for a problem I want to resolve. It goes like this:
~ Goal: flatten a nested list into one number
If the object is a list, replace the list with the sum of its atoms.
With nested lists, flatten the innermost lists first and work from there.
Example:
(CONDENSE '(2 3 4 (3 1 1 1) (2 3 (1 2)) 5))
(2 3 4 (6) (2 3 (3)) 5)
(2 3 4 (6) (8) 5)
(28)
=> 28
I've tried to implement the flatten list function for this problem and I ended up with this:
(defun condense (lst)
(cond
((null lst) nil)
((atom lst) (list lst)))
(t (append (flatten (apply #'+ (cdr lst))))))
But it gives me errors :(
Could anyone explain to me what is wrong with my processing/code? How can I improve it?
UPDATE: JUNE 5 2012
(defun condense(lxt)
(typecase lxt
(number (abs lxt))
(list
(if (all-atoms lxt)
(calculate lxt)
(condense (mapcar #'condense lxt))))))
So here, in this code, my true intent is shown. I have a function calculate that performs a calculation based off the values in the list. It is not necessarily the same operation each time. Also, I am aware that I am returning the absolute value of the number; I did this because I couldn't find another way to return the number itself. I need to find a way to return the number if the lxt is a number. And I had it recurse two times at the bottom, because this is one way that it loops on itself infinitely until it computes a single number. NOTE: this function doesn't implement a flatten function anymore nor does it use anything from it.
Imagine you have your function already. What does it get? What must it produce?
Given an atom, what does it return? Given a simple list of atoms, what should it return?
(defun condense (x)
(typecase x
(number
; then what?
(condense-number x))
(list
; then what?
(if (all-atoms x)
(condense-list-of-atoms x) ; how to do that?
(process-further-somehow
(condense-lists-inside x))))
; what other clauses, if any, must be here?
))
What must condense-lists-inside do? According to your description, it is to condense the nested lists inside - each into a number, and leave the atoms intact. So it will leave a list of numbers. To process that further somehow, we already "have" a function, condense-list-of-atoms, right?
Now, how to implement condense-lists-inside? That's easy,
(defun condense-lists-inside (xs)
(mapcar #'dowhat xs))
Do what? Why, condense, of course! Remember, we imagine we have it already. As long as it gets what it's meant to get, it shall produce what it is designed to produce. Namely, given an atom or a list (with possibly nested lists inside), it will produce a number.
So now, fill in the blanks, and simplify. In particular, see whether you really need the all-atoms check.
edit: actually, using typecase was an unfortunate choice, as it treats NIL as LIST. We need to treat NIL differently, to return a "zero value" instead. So it's better to use the usual (cond ((null x) ...) ((numberp x) ...) ((listp x) ...) ... ) construct.
About your new code: you've erred: to process the list of atoms returned after (mapcar #'condense x), we have a function calculate that does that, no need to go so far back as to condense itself. When you substitute calculate there, it will become evident that the check for all-atoms is not needed at all; it was only a pedagogical device, to ease the development of the code. :) It is OK to make superfluous choices when we develop, if we then simplify them away, after we've achieved the goal of correctness!
But, removing the all-atoms check will break your requirement #2. The calculation will then proceed as follows
(CONDENSE '(2 3 4 (3 1 1 1) (2 3 (1 2)) 5))
==
(calculate (mapcar #'condense '(2 3 4 (3 1 1 1) (2 3 (1 2)) 5)))
==
(calculate (list 2 3 4 (condense '(3 1 1 1)) (condense '(2 3 (1 2))) 5))
==
(calculate (list 2 3 4 (calculate '(3 1 1 1))
(calculate (list 2 3 (calculate '(1 2)))) 5))
==
(calculate (list 2 3 4 6 (calculate '(2 3 3)) 5))
==
(calculate (list 2 3 4 6 8 5))
==
28
I.e. it'll proceed in left-to-right fashion instead of the from the deepest-nested level out. Imagining the nested list as a tree (which it is), this would "munch" on the tree from its deepest left corner up and to the right; the code with all-atoms check would proceed strictly by the levels up.
So the final simplified code is:
(defun condense (x)
(if (listp x)
(reduce #'+ (mapcar #'condense x))
(abs x)))
a remark: Looking at that last illustration of reduction sequence, a clear picture emerges - of replacing each node in the argument tree with a calculate application. That is a clear case of folding, just such that is done over a tree instead of a plain list, as reduce is.
This can be directly coded with what's known as "car-cdr recursion", replacing each cons cell with an application of a combining function f on two results of recursive calls into car and cdr components of the cell:
(defun condense (x) (reduce-tree x #'+ 0))
(defun reduce-tree (x f z)
(labels ((g (x)
(cond
((consp x) (funcall f (g (car x)) (g (cdr x))))
((numberp x) x)
((null x) z)
(T (error "not a number")))))
(g x)))
As you can see this version is highly recursive, which is not that good.
Is this homework? If so, please mark it as such. Some hints:
are you sure the 'condensation' of the empty list in nil? (maybe you should return a number?)
are you sure the condensation of one element is a list? (maybe you should return a number?)
are you sure the condensation of the last case is a list? (shouldn't you return a number)?
In short, how is your condense ever going to return 28 if all your returned values are lists?
Task: With nested lists, flatten the innermost lists first and work from there
sum
flatten lists
For sum use REDUCE, not APPLY.
For flatten lists you need a loop. Lisp already provides specialized mapping functions.
Slightly more advanced: both the sum and the flatten can be done by a call to REDUCE.
You can also write down the recursion without using a higher-order function like APPLY, REDUCE, ... That's a bit more work.
Here's added the explanation of the errors you were having, actually you were close to solving your problem, just a bit more effort and you would get it right.
; compiling (DEFUN CONDENSE ...)
; file: /tmp/file8dCll3
; in: DEFUN CONDENSE
; (T (APPEND (FLATTEN (APPLY #'+ (CDR LST)))))
;
; caught WARNING:
; The function T is undefined, and its name is reserved
; by ANSI CL so that even
; if it were defined later, the code doing so would not be portable.
;
; compilation unit finished
; Undefined function:
; T
; caught 1 WARNING condition
;STYLE-WARNING: redefining CONDENSE in DEFUN
(defun condense (lst)
(cond
((null lst) nil)
((atom lst) (list lst)))
;.------- this is a function call, not a condition
;| (you closed the parens too early)
(t (append (flatten (apply #'+ (cdr lst))))))
;; Argument Y is not a NUMBER: (3 1 1 1)
;; [Condition of type SIMPLE-TYPE-ERROR]
(defun condense (lst)
(cond
((null lst) nil)
((atom lst) (list lst)); .-- not a number!
;You are calling #'+ -------. |
;on something, which | '(3 4 (3 1 1 1) (2 3 (1 2)) 5)
; is not a number. | |
(t (append (flatten (apply #'+ (cdr lst)))))))
;; You probably wanted to flatten first, and then sum
(defun condense (lst)
(cond
((null lst) nil); .--- returns just the
((atom lst) (list lst)); / atom 28, you can
; .---------------------/ just remove it.
(t (append (apply #'+ (flatten lst))))))
;; Now, you are lucky that append would just return the
;; atom if it's not a list
(defun condense (lst)
(cond
((null lst) nil)
((atom lst) (list lst))
(t (apply #'+ (flatten lst)))))
;; Again, you are lucky because (apply can take enough arguments
;; while your list is reasonably small - this will not always be
;; the case, that is why you need to use something more durable,
;; for example, reduce.
(defun condense (lst)
(cond
((null lst) nil)
((atom lst) (list lst))
(t (reduce #'+ (flatten lst)))))
;; Whoa!
(condense '(2 3 4 (3 1 1 1) (2 3 (1 2)) 5))
This is all given the flatten function actually works.
If your lisp already implements flatten and reduce functions (such as Clojure, which I will use here), you can just do something like:
user=> (defn condense [l] (reduce + 0 (flatten l)))
#'user/condense
user=> (condense [1 [2 [[3 4] 5]]])
15
user=>
Failing that, a naive implementation of those functions might be:
(defn flatten [l]
(cond (nil? l) l
(coll? l) (let [[h & t] l]
(concat (flatten h) (flatten t)))
true [l]))
and:
(defn reduce [op initial-value [h & t]]
(if (nil? t)
(op initial-value h)
(op initial-value (reduce op h t))))
But make sure to check the semantics of the particular Lisp you are using. Also, if you are implementing reduce and flatten, you may want to make them tail recursive which I didn't so as to maintain clarity.
In Common Lisp you would do something like:
(defun flatten (l)
(cond ((null l) l)
((atom l) (list l))
(t (append (flatten (car l))
(flatten (cdr l))))))
and use apply instead of reduce:
(defun condense (l) (apply #'+ (flatten l)))
I'm currently working on a LISP exercise for a small project and need severe help. This may be more or less of a beginner's question but I'm absolutely lost on writing a certain function that takes in two unevaluated functions and spits out the result dependent on if the variables were given an assignment or not.
An example would be
(setq p1 '(+ x (* x (- y (/ z 2)))))
Where
(evalexp p1 '( (x 2) (z 8) ))
returns (+ 2 (* 2 (- y 4)))
My goal is to write the evalexp function but I can't even think of where to start.
So far I have
(defun evalexp (e b) )
.. not very much. If anyone could please help or lead me in a good direction I'd be more than appreciative.
Here's a full solution. It's pretty straightforward, so I'll leave out a full explanation. Ask me in the comments if there's anything you can't figure out yourself.
(Using eval to do the actual evaluation might not be what you want in your exercise/project. Look up "meta-circular interpreter" for another way.)
(defun apply-env (exp env)
(reduce (lambda (exp bdg) (subst (cadr bdg) (car bdg) exp))
env :initial-value exp))
(defun try-eval (exp)
(if (atom exp)
exp
(let ((exp (mapcar #'try-eval exp)))
(if (every #'numberp (cdr exp))
(eval exp)
exp))))
(defun evalexp (exp env)
(try-eval (apply-env exp env)))
Here's a hint, this is how you might do it (in pseudocode):
function replace(vars, list):
for each element of list:
if it's an atom:
if there's an association in vars:
replace atom with value in vars
else:
leave atom alone
else:
recursively apply replace to the sublist
There will certainly be some details to work out as you convert this to Lisp code.