I need an incf function which does some bounds checking during the increment:
val := val + delta
if val >= 1.0
then return 1.0
else return val
I can write this using incf:
(defun incf-bounded(val delta)
(incf val delta)
(if (>= val 1.0) 1.0 val))
In such case I need to use this like (setf x (incf-bounded x delta)). But how do I write one which I can use like (incf-bounded x delta), i.e., where x will be modified?
This is a good use case for define-modify-macro (which has also been described in what is to append as push is to cons, in Lisp?, but the present case is simpler). First, write your bounded sum as a function. This is pretty straightforward; it takes val and delta and returns 1.0 if their sum is greater than 1.0, and their sum otherwise. Based on the pseudo code and Lisp code you posted, this could be:
(defun sum-bounded (val delta)
(if (>= (+ val delta) 1.0)
1.0
(+ val delta)))
Actually, for just computing this value, you can use:
(defun sum-bounded (val delta)
(min 1.0 (+ val delta)))
Now you use define-modify-macro to define a macro incf-bounded:
(define-modify-macro incf-bounded (delta) sum-bounded)
The macro takes a place as its first argument and delta as a second. It safely retrieves the value from the place, computes sum-bounded with that value and delta, and then stores the result back into the place. “Safely” here means that it avoids possible problems with multiple evaluation, as Lars Brinkhoff's wisely warns against. Then you just use it:
(let ((x .5))
(incf-bounded x .3)
(print x) ; prints 0.8
(incf-bounded x .3)
(print x)) ; prints 1.0 (not 1.1)
For more complicated cases where the place that would be modified isn't naturally the first argument to the macro that you want, you'd need to write your own macro and use get-setf-expansion, but this is explained in more detail in
what is to append as push is to cons, in Lisp?
Code all together for easy copy & paste
(defun sum-bounded (val delta)
"Returns the lesser of 1.0 or the sum of val and delta."
(min 1.0 (+ val delta)))
(define-modify-macro incf-bounded (delta) sum-bounded
"(incf-bounded place delta) computes the sum of the value of the
place and delta, and assigns the lesser of 1.0 and the sum of the value
and delta to place.")
(defun demo ()
(let ((x .5))
(incf-bounded x .3)
(print x) ; prints 0.8
(incf-bounded x .3)
(print x))) ; prints 1.0 (not 1.1)
You may want to be careful about val, if you want it to be a place which can have side effects:
(defmacro incf-bounded (form delta &environment env)
(multiple-value-bind (temps vals vars writer reader)
(get-setf-expansion form env)
`(let* (,#(mapcar #'list temps vals)
(,(first vars) (min (+ ,delta ,reader) 1.0))) ;Edited, see comments.
,writer)))
Try it with e.g.
(let ((list (list 0 0.5 1)))
(loop with i = -1 repeat 3 do (incf-bounded (nth (incf i) list) 0.5))
list)
(This looks needlessly complicated, because I wanted a side effect in the first argument to incf-bounded.)
Related
CL-USER> (a-sum 0 3)
->> 6
I wrote this program :
(defun a-sum (x y)
(if (and (> x -1) (> y -1))
(do ((i 0 (1+ i))
(sum 0)
(num x))
((equal i (+ (- y x) 1)))
(setq sum (+ sum num))
(setq num (+ num 1))
sum)
(print " NOPE")))
put if I run it in the terminal it returns nil and not the answer stated above;
can someone help with the problem so it returns the value then Boolean.
DO,DO* Syntax
The entry for DO,DO* says that the syntax is as follows:
do ({var | (var [init-form [step-form]])}*)
(end-test-form result-form*)
declaration*
{tag | statement}*
The body is used as a list of statements and no intermediate value in this body is used as the result form of the do form. Instead, the do form evaluates as the last expression in result-form*, which defaults to nil.
(do ((i 0 (1+ i))
(sum 0)
(num x))
((equal i (+ (- y x) 1))
;;; RESULT FORMS HERE
)
(setq sum (+ sum num)) ;; (*)
(setq num (+ num 1)) ;; (*)
sum ;; (*)
)
All the expressions marked commented (*) above are used for side-effects only: the result of their evaluation is unused and discarded.
Problem statement
It is not clear to me what Σpi=ni means, and your code does not seem to compute something that could be expressed as that mathematical expression.
One red flag for example is that if (+ (- y x) 1) is negative (i.e. if y < x-1, for example y=1,x=3), then your loop never terminates because i, which is positive or null, will never be equal to the other term which is negative.
I would try to rewrite the problem statement more clearly, and maybe try first a recursive version of your algorithm (whichever is easier to express).
Remarks
Please indent/format your code.
Instead of adding setq statements in the body, try to see if you can define them in the iteration clauses of the loop (since I'm not sure what you are trying to achieve, the following example is only a rewrite of your code):
(do ((i 0 (1+ i))
(sum 0 (+ sum num)
(num x (1+ num))
(... sum))
Consider what value(s) a function returns. It's the value of the last form evaluated. In your case, that appears to be a do or maybe a setq or print (It's difficult to read as it's formatted now, and I don't have question edit privileges).
In short, the form that's returning the value for the function looks to be one evaluated for side-effects instead of returning a value.
I'm new to lisp programming and I'm trying to create a program that accept six numbers and check whether each number is either odd or even number.
(princ"Input six number: ")
(setq a(read))
(setq b(read))
(setq c(read))
(setq d(read))
(setq e(read))
(setq f(read))
(format t "~% ~d" a)
(format t "~% ~d" b)
(format t "~% ~d" c)
(format t "~% ~d" d)
(format t "~% ~d" e)
(format t "~% ~d" f)
(if(= 0(mod a 2))
(print"even")
(print"odd"))
(if(= 0(mod b 2))
(print"even")
(print"odd"))
(if(= 0(mod c 2))
(print"even")
(print"odd"))
(if(= 0(mod d 2))
(print"even")
(print"odd"))
(if(= 0(mod e 2))
(print"even")
(print"odd"))
(if(= 0(mod f 2))
(print"even")
(print"odd"))
(terpri)
You have a lot of code that looks like this:
(if(= 0(mod ... 2))
(print"even")
(print"odd"))
(this might be a copy/paste problem but in your question they are indented more and more to the right. They are however not nested, they are all at the same depth (they are toplevel expressions) so by convention they should not be indented).
A first step would be to factor them using a function like this one:
(defun check-even-odd (number)
(if (= 0 (mod number 2))
(print "even")
(print "odd")))
The above defines a function named check-even-odd of one parameter number, and it applies the same logic you originally had for any arbitrary number.
The rest of your code can be simplified as:
(check-even-odd a)
(check-even-odd b)
(check-even-odd c)
(check-even-odd d)
(check-even-odd e)
(check-even-odd f)
Now, you can define two additional global variables:
(defparameter total-even 0)
(defparameter total-odd 0)
Each of them holds a sum, and is initialized to 0.
You can rewrite the check-even-odd function as follows to update the counters. First of all, let's just rewrite the current code by using cond, since we are going to need to perform multiple actions in each case, and if only accepts one expression for each branch (the combination if and progn is a bit ugly):
(defun check-even-odd (number)
(cond
((= 0 (mod number 2))
(print "even"))
(t
(print "odd"))))
This above behaves as the original code.
In order to increment a variable by a certain amount, you can use INCF:
(defun check-even-odd (number)
(cond
((= 0 (mod number 2))
(print "even")
(incf total-even number))
(t
(print "odd")
(incf total-odd number))))
When you execute your whole script, the total will be initialized to zero, then each call to check-even-odd will add the number to the appropriate counter.
Notes:
You may find other places where you can use functions to abstract duplicated code
You should use defparameter instead of setq when initializing a, b, etc, because otherwise the variables are not declared and calling setq on undeclared variables is not standard
In fact, it is possible to rewrite the whole program without having any global state, this could be a good next exercise
You can generalize for less or more numbers instead of 6, you would need to write a loop or a recursive function to repeat the same code an arbitrary amount of time
Input/output may need to be flushed (see finish-output, clear-input) otherwise you could experience strange behavior when the underlying stream is buffered.
Just started learning lisp. I have no idea why I am getting these errors or even what they mean. I am simply trying to code an approximation of pi using the Gregory-Leibniz series, here is the code.
(defun gl (n)
(defparameter x 0) ;init variable to hold our runnning sum
(loop for y from 0 to n ;number of iterations, starting from 0 to desired n
(if (= y 0) ;if n is 0 then we just want 4
(defparameter w 4))
(if (> y 0) ;else, 4*(-1^y)/((2 * y)+1)
(defparameter w (* 4 (/ (exp -1 y) (+ (* 2 y) 1)))))
(+ x w)) ;add to our running sum
(write x)) ;once loop is over, print x.
I have tried using setq, defvar, let etc. instead of defparameter but I still get "Undeclared free variable X".
I also get the error "Unused lexical variable N" even though I am using it for my loop, which is weird also.
How can I fix this and why is it happening? Thanks!
Here is the code after Emacs auto-indented it:
(defun gl (n)
(defparameter x 0)
(loop for y from 0 to n
(if (= y 0)
(defparameter w 4))
(if (> y 0)
(defparameter w (* 4 (/ (exp -1 y) (+ (* 2 y) 1)))))
(+ x w))
(write x))
Compiling the following code with SBCL gives one error and two warnings.
One warning says that x is undefined.
You should not call defparameter from inside your function, since defvar and defparameter are used to declare dynamic variables and to set their value in the global scope. Prefer to have let bindings, or, since you already are using a loop, a with clause. When you want to modify a binding, use setf.
The errors comes from the macroexpansion of LOOP, which is malformed. For SBCL, that means that the code is treated as dead-code for the rest of the function compilation; that explains why n appears not to be used, which is what the second warning is about.
There are various fixes remaining to be done:
Use function EXPT, not EXP.
Calling (+ x w) only computes a value but does not modify x, the result is useless.
Prefer using if as expression, like a ternary operator in other languages, in your case the code can be simplified
Adding one can be done with function 1+ (that's the name of the function, not a special syntax for adding constants)
The write operation is rarely needed, especially if you are computing a mathematical formula; just return the value, and the REPL will print it automatically.
Small corrections that make your code works:
(defun gl (n)
(let ((x 0))
(loop
for y from 0 to n
for w = (if (= y 0)
4
(* 4 (/ (expt -1 y) (+ (* 2 y) 1))))
do (setf x (+ x w)))
(write x)))
I would personally get rid of x and w, and use a SUM loop clause.
(defun gl (n)
(loop
for y from 0 to n
sum (if (zerop y)
4
(* 4 (/ (expt -1 y)
(1+ (* 2 y)))))))
In the following code, I am trying to understand how the variable whatami gets its value. In following the logic, I see that the procedure (lambda (y) (/ x y)) is the parameter that I am passing to the method average-damp, and is represented within that method as the variable f. It seems as though (/ x y) and (average (f whatami) whatami) need to be executed, but I can't figure out the order of execution. Any help is appreciated.
(define (average x y)
(/ (+ x y) 2))
(define (fixed-point f start)
(define tolerance 0.00001)
(define (close-enuf? u v)
(< (abs (- u v)) tolerance))
(define (iter old new)
(if (close-enuf? old new)
new
(iter new (f new))))
(iter start (f start)))
(define average-damp
(lambda (f)
(lambda (whatami) (average (f whatami) whatami))))
; square root with average damping
(define (_sqrt x)
(fixed-point
(average-damp (lambda (y) (/ x y)))
1))
(_sqrt 4.0)
The average-damp procedure takes a procedure as its argument and returns a procedure as its value. When given a procedure that takes one argument, average-damp returns another procedure that computes the average of the values before and after applying the original function f to its argument. It's inside the fixed-point procedure where that returned function is applied (iteratively).
So the average-damp procedure doesn't execute either (/ x y) or (average(f whatami) whatami) at all, it just uses the function passed to it to create a new function that it returns.
I decided to learn LISP today, and have been playing around with it for a bit. I wrote a simple baby function just to test my understanding, and now understand that my understanding doesn't understand as much as I had understood it to understand. :D
Anyway, here is the function. The idea is that when it is called, e.g. (esexp base x) it should return the value base^x. So (esexp 3 4) = 3^4 = 81.
(I am using the CMU implementation of Common Lisp, if that matters.)
(defun esexp (base x)
(if (= x 0)
1
(if (< x 0)
(/ esexp (base (+ x 1)) base)
(* esexp (base (+ x 1)) base))))
This doesn't work. I get errors that look like (Warning: This variable is undefined: SLBEXP) and (Error in KERNEL::UNBOUND-SYMBOL-ERROR-HANDLER: the variable SLBEXP is unbound.) So. What am I doing wrong? AND would there be a better (or more LISP-ish way) to write this function?
ETA
Corrected code:
(defun esexp (base x)
(if (= x 0)
1
(if (< x 0)
(/ (esexp base (+ x 1)) base)
(* (esexp base (- x 1)) base))))
esexp(base (+ x 1))
should be
(esexp base (+ x 1))
esexp is a function just like +. The syntax for invoking a function is
(function-name arg1 arg2 ...)
The technical explanation of the error: the compiler was parsing the code:
(/ esexp(base (+ x 1)) base)
as this:
(/ esexp (base (+ x 1)) base)
which says:
first, add 1 to the parameter x
then, invoke a function called base with the result above.
divide the value of a variable called esexp by the result above.
then, divide that result by the parameter base. (The divide operator in Common Lisp can take more than two arguments.)
You see the trick? When a word appears as the first item in a s-expression (and that s-expression isn't quoted), it's usually treated as the name of a function you want to invoke. Otherwise, it's treated as the name of a variable whose value you want to retrieve. Further, in Common Lisp a symbol like esexp can be bound to both a function value and a variable value at the same time; context or special expressions like #'esexp (which means the function) are used to figure out which one you mean.
The compiler was telling you that, though esexp was bound to a function with your defun statement, it had not yet been bound to a variable value, and therefore could not be used as such. Hence, the error.
Just a note about the code. I believe it should be
(defun esexp (base x)
(if (= x 0)
1
(if (< x 0)
(/ (esexp(base (+ x 1)) base))
(* (esexp(base (- x 1)) base))))
Otherwise the function will never terminate. (you had (* (esexp(base (+ x 1)) base)))))