In this file I get 9 warnings of "assumed special". They are
;;;*** Warning in CHECK-ROW: CHECKARRAY assumed special in SETQ
;;;*** Warning in CHECK-ROW: RESULT assumed special in SETQ
;;;*** Warning in CHECK-ROW: CHECKARRAY assumed special
;;;*** Warning in CHECK-ROW: CHECKARRAY assumed special
;;;*** Warning in CHECK-ROW: CHECKARRAY assumed special
;;;*** Warning in CHECK-ROW: CHECKARRAY assumed special
;;;*** Warning in CHECK-ROW: CHECKARRAY assumed special
;;;*** Warning in CHECK-ROW: RESULT assumed special in SETQ
;;;*** Warning in CHECK-ROW: RESULT assumed special
The whole file is just two functions -
(defun get-element (x y board)
(nth y (nth x board)))
(defun check-row (row board)
(setq checkarray (make-array 9))
(setq result T)
(fill checkarray 0)
(loop for i upto 8 do
(setf (aref checkarray (- (get-element row i board) 1))
(+ (aref checkarray (- (get-element row i board) 1)) 1))
)
(loop for i upto 8 do
(if (or (= (aref checkarray i) 0) (> (aref checkarray i) 1))
(setq result nil) ())
)
result)
I don't get any errors and the functions seem to work fine. So why does it say this? And how can I fix it?
Any variable not defined may be assumed to be special. Another interpretation also does not really make sense.
You may either
introduce your variables as global special variables using DEFVAR or DEFPARAMETER
or
introduce your variables as local lexical variables using DEFUN, LAMBDA, FLET, LABELS, LET, LET* or others
or
declare your variables as special or declare the variable reference as special. Usually this is not what one wants.
Anyway, SETQ does not define a or declare a variable. All it does is that it sets an existing variable to some value.
Avoid setting undefined/declared variables with SETQ in code. Its exact consequences are undefined in the ANSI Common Lisp standard.
Rainer Joswig's answer is correct in general. In your case, I don't see any need for these variables to be global, so the best thing to do is use let to make them local to the body of your function:
(defun check-row (row board)
(let ((checkarray (make-array 9)) (result t))
(fill checkarray 0)
(loop for i upto 8 do
(setf (aref checkarray (- (get-element row i board) 1))
(+ (aref checkarray (- (get-element row i board) 1)) 1)))
(loop for i upto 8 do
(if (or (= (aref checkarray i) 0) (> (aref checkarray i) 1))
(setq result nil) ()))
result))
Edit: Also, since you're just adding 1 to a place, you can use incf instead of that long setf:
(defun check-row (row board)
(let ((checkarray (make-array 9)) (result t))
(fill checkarray 0)
(loop for i upto 8 do
(incf (aref checkarray (- (get-element row i board) 1))))
(loop for i upto 8 do
(if (or (= (aref checkarray i) 0) (> (aref checkarray i) 1))
(setq result nil) ()))
result))
The difference is that setq is not, strictly speaking, supposed to be used to define a variable (I am not exactly sure why, since it does define a variable).
Use defvar for globals and the let construct for locals.
Related
I am making a console Lisp survival game and I am trying to add a function where until a = b, show "." every second. Then, when a = b, set a "hurt" variable to true, and if/when that variable is true, subtract "health" by 1 until the "use-medkit" function is invoked by the user and the "hurt" variable is set false and you exit both loops.
The problem I am having is when I am prompted to use the "use-medkit" function and I type it in, it doesn't evaluate anything that I input and keeps subtracting 1 from "health". How can I call a user-inputted function while a loop is running?
Here is my code:
(setq a (random 11)) ; Random from 0 - 10
(setq b (random 11)) ; ^^^^^^^^^^^^^^^^^^
(setq hurt 0)
(setq repair 0)
(setq health 999)
(defun use-medkit ()
(setq repair 1))
(defun get-hurt ()
(loop
(progn
(setq a (random 11))
(setq b (random 11))
(progn
(princ ".")
(sleep 1)))
(if (eq a b) (progn
(setq hurt 1)
(when (eq hurt 1) (progn
(format t "~%You are hurt!~%You will lose 1 hp every 10 seconds~%~%Type use-medkit to stop the bleeding~%")
(loop
(progn
(- 1 health)
(sleep 10))
;(format t "health: ~A~%" health)
(when (eq repair 1) (progn
(return "You stopped the bleeding") (setq hurt 0) (setq repair 0))))))))))
So a program can’t do two things at once. In particular if you’re busy printing dots, sleeping and subtracting 1 from 999 then you won’t pause to see if there’s another command coming.
Unfortunately solving this problem is hard. The nicest solution in a terminal would probably use something like ncurses. Additionally there is no standard way to control input buffering. In lieu of that, here is a simple way you can do a bit of concurrency and some prompts. You might want to use a proper async library instead.
(defun maybe-read (input-stream recording-stream)
(when (listen input-stream)
(let ((char (read-char input-stream)))
(if (char= char #\Newline)
t
(progn (write-char char recording-stream) (maybe-read))))))
(defun make-partial-reader (input-stream)
(list input-stream (make-string-output-stream)))
(defun partial-read (reader)
(when (apply #'maybe-read reader)
(get-output-stream-string (second reader))))
(defun how-long-until (time)
(let ((gap
(/ (- time (get-internal-run-time)) internal-time-units-per-second)))
(cond ((< gap 0) (values 0 :late))
((<= gap 0.001) (values 0 :now))
(T (values (- gap 0.001) :soon)))))
(defun sleep-until (time)
(multiple-value-bind (span type)
(how-long-until time)
(when (> span 60) (warn “long wait!”)
(case type
(:late nil)
(:now t)
(:soon
(sleep span)
(unless (sleep-until time) (warn “poor timekeeping”))
t))))
(defmacro with-prompt-and-scheduler ((schedule) (line &optional (input *standard-input*)) &body handle-line-input)
(let ((reader (gensym)) (insched (gensym)))
`(let ((,reader (make-partial-reader ,input) (,insched)))
(flet ((,schedule (in fun &aux (at (+ (get-internal-run-time) (* in internal-time-units-per-second))))
(if (null ,insched) (push (cons at fun) schedule)
(loop for s on ,insched
for ((at2) . y) = s
if (< at at2)
do (psetf (car s) (cons at fun)
(cdr s) (cons (car s) (cdr s)))
(finish-loop)
unless y do (setf (cdr s) (acons at fun nil)) (finish-loop)))))
(loop
(if ,insched
(let ((,insched (pop ,insched)))
(when (sleep-until (car ,insched))
(let ((,line (partial-read ,reader)))
(when ,line ,#handle-line-input)))
(funcall (cdr ,insched)))
(let ((,line (concatenate 'string (get-output-stream-string (second ,reader)) (read-line (first ,reader)))))
,#handle-line))))))))
And then you could use it like:
(let ((count 0))
(with-prompt-and-scheduler (schedule) (line)
(let ((n (read-from-string line)))
(when (realp n)
(schedule n (let ((x (incf count))) (lambda () (format t "Ding ~a ~a~%" x count) (finish-output))))))))
And after running that input 10, then on the next line 5. If you do that quickly you’ll get:
Ding 2 2
Ding 1 2
With the first line appearing after 5 seconds and the second after 10. If you are slow you should get:
Ding 1 1
Ding 2 2
With the first line coming 10 seconds after you enter 10 and the second line coming 5 seconds after you enter 5.
Hopefully this can give you an idea of how to make a program seem to do two things at once.
I'm new to lisp, trying to understand how lisp works, and I don't know how exactly to work with a local variable inside a large function.
here I have a little exc that I send a number to a function and if it is divisible by 3, 5 and 7 I must return a list of (by3by5by7), if only by 7, return (by7) and so on....
here is my code:
(defun checknum(n)
let* (resultt '() ) (
if(not(and(plusp n ) (integerp n))) (cons nil resultt) (progn
(if (zerop (mod n 7)) (cons 'by7 resultt) (cons nil resultt))
(if (zerop (mod n 5)) (cons 'by5 resultt) (cons nil resultt))
(if (zerop (mod n 3)) (cons 'by3 resultt) (cons nil resultt) )) ))
but if i send 21 for ex, I only get nil, instead of (by3by7) I guess the local variable is not affected by my if statements and I don't know how to do it...
(cons x y) creates a new cons cell and disposes of the result. To change the value of a variable you need to use setq, setf, push or the like, for example:
(defun checknum (n)
(let ((resultt nil))
(when (and (plusp n) (integerp n))
(when (zerop (mod n 7)) (push 'by7 resultt))
(when (zerop (mod n 5)) (push 'by5 resultt))
(when (zerop (mod n 3)) (push 'by3 resultt)))
resultt))
or perhaps, more elegantly using an internal function to factor out the repetition:
(defun checknum (n)
(when (and (plusp n) (integerp n))
(labels ((sub (d nsym res)
(if (zerop (mod n d))
(cons nsym res)
res)))
(sub 7 'by7
(sub 5 'by5
(sub 3 'by3 nil)))))
Testing:
CL-USER> (checknum 12)
(BY3)
CL-USER> (checknum 15)
(BY3 BY5)
CL-USER> (checknum 105)
(BY3 BY5 BY7)
CL-USER> (checknum 21)
(BY3 BY7)
Most lisp forms/functions don't modify their arguments. The ones that do will be explicitly documented as doing so. See adjoin and pushnew, for instance, or remove and delete.
To the point of 'trying to understand how lisp works', writing the same function in various different ways helped me a lot, so you might want to think about how you can write your function without modifying a variable at all, and why and when you would want to / not want to use destructive modifications.
Something like the below makes two passes, and will be too slow if there are a large quantity of numbers you need to check, but doesn't destructively modify anything.
(defun checknum (n)
(remove nil
(mapcar #'(lambda (m sym)
(when (zerop (mod n m)) sym))
'(7 5 3)
'(by7 by5 by3))))
The above approach can be written to not require two passes, etc.
Quite often I need to replace subsequence of certain elements with another sequence of the same type, but, probably with different length. Implementation of such function is no challenge, this is what I use now:
(defun substitute* (new old where &key key (test #'eql))
(funcall (alambda (rest)
(aif (search old rest :key key :test test)
(concatenate (etypecase rest
(string 'string)
(vector 'vector)
(list 'list))
(subseq rest 0 it)
new
(self (subseq rest (+ it (length old)))))
rest))
where))
Works like this:
CL-USER> (substitute* '(x y) '(z) '(1 z 5 8 y z))
(1 X Y 5 8 Y X Y)
CL-USER> (substitute* "green button" "red button"
"here are red indicator, red button and red wire")
"here are red indicator, green button and red wire"
CL-USER> (substitute* #(4) #(2 2) #(2 2 2 2 2))
#(4 4 2)
You see, it's very handy and useful, so I've feeling that I'm reinventing wheel and it must be in the standard library, I just don't know its name (sometimes names are not obvious, you may search for filter while what you need is set-difference).
As a result of compromise between clarity and efficiency:
(defun substitute* (new old where &key key (test #'eql))
(let ((type (etypecase where
(string 'string)
(vector 'vector)
(list 'list)))
(new (coerce new 'list))
(old (coerce old 'list))
(where (coerce where 'list)))
(coerce (funcall (alambda (rest)
(aif (search old rest :key key :test test)
(append (remove-if (constantly t) rest :start it)
new
(self (nthcdr (+ it (length old)) rest)))
rest))
where)
type)))
I don't think that there's any standard function for this. It's more complicated than the standard replace family of functions. Those can operate destructively because you know in advance that you can replace element by element. Even in that case, it's still somewhat difficult to do this efficiently, because the access time for lists and vectors is very different, so general-purpose functions like subseq can be problematic. As Rainer Joswig pointed out in a comment:
It's kind of unfortunate that for many algorithms over sequences there
is no single efficient implementation. I see often that there are two
versions, one for lists and one for vectors, which then get hidden
behind a dispatching function. For a hack a simple common version is
fine, but for a library function, often there are different
implementations - like shown here.
(In fact, in doing a bit of research on whether some library contains a function for this, one of the first Google results I got was a question on Code Review, Generic sequence splitter in Common Lisp, in which Rainer and I both had some comment similar to those here.)
A version for lists
However, your implementation is rather inefficient because it makes multiple copies of the the remainders of sequences. E.g., when you replace (z) in (1 z 2 z 3 z), with (x y), you'll first make (3 x y), then copy it in making (2 x y 3 z y), and then you'll copy that in making (1 x y 2 x y 3 x y). You might be better off in doing one pass over the sequence, determining the indices of the subsequences to replace, or collecting the bits that need to don't need to be replaced, etc. You'll probably want separate implementations for lists and for other sequences. E.g., with a list, you might do:
(defun splice-replace-list (old new list)
(do ((new (coerce new 'list))
(old-len (length old))
(parts '()))
((endp list)
(reduce 'append (nreverse parts) :from-end t))
(let ((pos (search old list)))
(push (subseq list 0 pos) parts)
(cond
((null pos)
(setf list nil))
(t
(push new parts)
(setf list (nthcdr (+ old-len pos) list)))))))
There are some optimizations you could make here, if you wanted. For instance, you could implement a search-list that, rather than returning the position of the first instance of the sought sequence, could return a copy of the head up until that point and the tail beginning with the sequence as multiple values, or even the copied head, and the tail after the sequence, since that's what you're really interested in, in this case. Additionally, you could do something a bit more efficient than (reduce 'append (nreverse parts) :from-end t) by not reversing parts, but using a reversed append. E.g.,
(flet ((xappend (l2 l1)
(append l1 l2)))
(reduce #'xappend '((5 6) (x y) (3 4) (x y))))
;=> (x y 3 4 x y 5 6)
I wrote this in a somewhat imperative style, but there's no reason that you can't use a functional style if you want. Be warned that not all Lisp implementation support tail call optimization, so it might be better to use do, but you certainly don't have to. Here's a more functional version:
(defun splice-replace-list (old new list)
(let ((new-list (coerce new 'list))
(old-len (length old)))
(labels ((keep-going (list parts)
(if (endp list)
(reduce 'append (nreverse parts) :from-end t)
(let* ((pos (search old list))
(parts (list* (subseq list 0 pos) parts)))
(if (null pos)
(keep-going '() parts)
(keep-going (nthcdr (+ old-len pos) list)
(list* new-list parts)))))))
(keep-going list '()))))
A version for vectors
For non lists, this is more difficult, because you don't have the specific sequence type that you're supposed to be using for the result. This is why functions like concatenate require a result-type argument. You can use array-element-type to get an element type for the input sequence, and then use make-array to get a sequence big enough to hold the result. That's trickier code, and will be more complicated. E.g., here's a first attempt. It's more complicated, but you'll get a result that's pretty close to the original vector type:
(defun splice-replace-vector (old new vector &aux (new-len (length new)))
(flet ((assemble-result (length parts)
(let ((result (make-array length :element-type (array-element-type vector)))
(start 0))
(dolist (part parts result)
(cond
((consp part)
(destructuring-bind (begin . end) part
(replace result vector :start1 start :start2 begin :end2 end)
(incf start (- end begin))))
(t
(replace result new :start1 start)
(incf start new-len)))))))
(do ((old-len (length old))
(total-len 0)
(start 0)
(indices '()))
((null start) (assemble-result total-len (nreverse indices)))
(let ((pos (search old vector :start2 start)))
(cond
((null pos)
(let ((vlength (length vector)))
(push (cons start vlength) indices)
(incf total-len (- vlength start))
(setf start nil)))
(t
(push (cons start pos) indices)
(push t indices)
(incf total-len (- pos start))
(incf total-len new-len)
(setf start (+ pos old-len))))))))
CL-USER> (splice-replace-vector '(#\z) '(#\x #\y) "12z")
"12xy"
CL-USER> (splice-replace-vector '(z) '(x y) #(x y))
#(X Y)
CL-USER> (splice-replace-vector '(z) '(x y) #(1 z 2 z 3 4 z))
#(1 X Y 2 X Y 3 4 X Y)
CL-USER> (splice-replace-vector '(#\z) #(#\x #\y) "1z2z34z")
"1xy2xy34xy"
If you only want to make one pass through the input vector, then you could use an adjustable array as the output, and append to it. An adjustable array will have a bit more overhead than a fixed size array, but it does make the code a bit simpler.
(defun splice-replace-vector (old new vector)
(do ((vlength (length vector))
(vnew (coerce new 'vector))
(nlength (length new))
(result (make-array 0
:element-type (array-element-type vector)
:adjustable t
:fill-pointer 0))
(start 0))
((eql start vlength) result)
(let ((pos (search old vector :start2 start)))
(cond
;; add the remaining elements in vector to result
((null pos)
(do () ((eql start vlength))
(vector-push-extend (aref vector start) result)
(incf start)))
;; add the elements between start and pos to the result,
;; add a copy of new to result, and increment start
;; accordingly
(t
;; the copying here could be improved with adjust-array,
;; and replace, instead of repeated calls to vector-push-extend
(do () ((eql start pos))
(vector-push-extend (aref vector start) result)
(incf start))
(loop for x across vnew
do (vector-push-extend x result))
(incf start (1- nlength)))))))
A “generic” version
Using these two functions, you could define a general splice-replace that checks the type of the original input sequence and calls the appropriate function:
(defun splice-replace (old new sequence)
(etypecase sequence
(list (splice-replace-list old new sequence))
(vector (splice-replace-vector old new sequence))))
CL-USER> (splice-replace #(z) '(x y) #(1 z 2 z 3 4 z))
#(1 X Y 2 X Y 3 4 X Y)
CL-USER> (splice-replace '(z) #(x y) '(1 z 2 z 3 4 z))
(1 X Y 2 X Y 3 4 X Y)
Here is what the function should do:
I am giving it list of "pairs" that look like (((a . b) . c) ((a . b) . c) ((a. b) . c) ...)
where:
a means if the vertex is visited 1 for yes 0 for no
b means what is the value of the shortest path to the vertex so far (if it is -1 it is infinity)
c is the number of the parent (if it has so far if it doesn't it is the number of the pair if you count the first pair for 1 second for 2 and etc.)
The function should return the number of the next unvisited pair (vertex) with the lowest cost of the path so far.
Example:
(((0 . 10) . 1) ((0 . 4) . 2) ((1 . 3) . 5) ...) here it should return the number 2.
Here is the code
(define (chooseNextLowest pairs num retV pointer)
(if (null? pairs)
retV
(if (checkIfPairVis (caar pairs))
(chooseNextLowest (cdr pairs) num retV (+ 1 pointer))
(if (= -1 num)
(chooseNextLowest (cdr pairs) (cdaar pairs) pointer (+ 1 pointer))
(if (not (= -1 (cdaar pairs)))
(if (< (cdaar pairs) num)
(chooseNextLowest (cdr pairs) (cdaar pairs) pointer (+ 1 pointer))
(chooseNextLowest (cdr pairs) num retV (+ 1 pointer))))))))
I have used some function that are predefined but I think it's clear by their names what they do.
I call it with num = -1 , retV = -1 and pointer = 1, since I use -1 for infinity and I am sure retV will be changed at least 1 time because everytime I call this function will be at least 1 unvisited pair.
They work fine also this function seems to work fine when I use it with some testPairs but when I use pairs that are returned from other function (since I have to choose everytime the lowest cost unvisited vertex after I update the information in the pairs) it doesnt return any value.
Maybe you will ask to see the other function too but I can't give it at the moment since if I give it I have to give the whole sorce code to make sense so I hope the mistake is somewhere here but I can't find it.
The other function return normal pairs in the type I want them ((a . b ) . c) and etc.
Thank you very much. I am sure I didn't make some things clear so If you have questions feel free to ask me.
After formatting the code it's obvious that in the second deepest if you are lacking a alternative. if without alternative is very new in Scheme but:
(if #f 'true) ;; ==> #undefined
Looking at your code, specially checkIfPairVis it seems you do caar and that's ok for the object, but not for the list with an object. The best way to eliminate such things would be to make accessors in your code which also will make your code easier to read:
(define (choose-next-lowest pairs num ret-v pointer)
;; accessor based on object
(define vertex-visited caar)
(define vertex-shortest cdar)
(define vertex-parents cdr)
(if (null? pairs)
ret-v
(let ((obj (car pairs)))
(cond
((check-if-pair-vis (vertex-visited obj))
(choose-next-lowest (cdr pairs) num ret-v (+ 1 pointer)))
...))))
After fixing that accessor I get 2 as you predicted.
It could be other things wrong of course. Seems to me you need to debug. In DrRacket IDE you could step through your code to ensure it works as designed.
PS: A named let will add accumulators and variables you don't need to expose:
(define (choose-next-lowest pairs)
(define vertex-visited caar)
(define vertex-shortest cdar)
(define vertex-parents cdr)
(define (vertex-visited? v)
(= 1 (vertex-visited v)))
(let rec ((pairs pairs) (num -1) (ret-v -1) (pointer 1))
(if (null? pairs)
ret-v
(let ((obj (car pairs)))
(cond
((vertex-visited? obj) (rec (cdr pairs) num ret-v (+ 1 pointer)))
((= -1 num) (rec (cdr pairs) (vertex-shortest obj) pointer (+ 1 pointer)))
((= -1 (vertex-shortest obj)) 'undefined) ;; something wrong here?
((< (vertex-shortest obj) num) (rec (cdr pairs) (vertex-shortest obj) pointer (+ 1 pointer)))
(else (rec (cdr pairs) num ret-v (+ 1 pointer))))))))
(choose-next-lowest '(((0 . 10) . 1) ((0 . 4) . 2) ((1 . 3) . 5))) ; ==> 2
Your conditional at (if (not (= -1 (cdaar pairs))) ... only has a consequent clause. Without an alternate clause the return of if is undefined (officially). Specifically:
(if (not (= -1 (cdaar pairs)))
(if (< (cdaar pairs) num)
(chooseNextLowest (cdr pairs) (cdaar pairs) pointer (+ 1 pointer))
(chooseNextLowest (cdr pairs) num retV (+ 1 pointer)))
<something here>)))))
Illustrating how if has an undefined return:
> (if #f 'yes 'no)
no
> (if #f 'yes)
> ; <= nothing printed as a return, just a prompt displayed.
This is related to this question: elisp functions as parameters and as return value
(defun avg-damp (n)
'(lambda(x) (/ n 2.0)))
Either
(funcall (avg-damp 6) 10)
or
((avg-damp 6) 10)
They gave errors of Symbol's value as variable is void: n and eval: Invalid function: (avg-damp 6) respectively.
The reason the first form does not work is that n is bound dynamically, not lexically:
(defun avg-damp (n)
(lexical-let ((n n))
(lambda(x) (/ x n))))
(funcall (avg-damp 3) 12)
==> 4
The reason the second form does not work is that Emacs Lisp is, like Common Lisp, a "lisp-2", not a "lisp-1"