lisp nested if statements - common-lisp

Hi im making a song database using Common lisp, im try to check the song information is well formed- ie it has 6 element in the list of song information, but I also want to check the types of each element in the list. I'm trying to do this using if statements, by first checking that there are 6 elements and if there are then checking the type of each element.
(defun checkSongInfo (par1 par2)
(if (= 6 (length (nth par1 par2))
(if (intergerp (first (nth par1 par2)))) 'complete 'incomplete))
so basically I have this code to begin with, I honestly have just started using LISP and am not familiar with it. Basically what im trying to do here is check for the 6 elements and if this is successful the success outcome of the if statement should be to then check the first element of the list, the song and list are passed in as parameters, these parts of my code should work as I have tried typing them directly into the terminal and they do what they should. The problem is with the if statements, at the moment it is telling me I have too few parameters. The first if statement works when I do
if(=6 (length (nth par1 par2))) 'complete 'incomplete
But when I put in the other if statement it give me the you have to few parameter for the if statement operator error message. It is probably just down to my misunderstanding of LISP and I have been searching for ages and cannot come up with a solution.

You are having problems with your parentheses and you have probably misspelled integerp in your code. I think you wanted to do this:
(defun checkSongInfo (par1 par2)
(if (= 6 (length (nth par1 par2))) ; added a ) here
(if (integerp (first (nth par1 par2))) ; removed a ) here, intergerp => integerp
'complete
'incomplete))) ; added a ) here
Looking at this you'll get incomplete if it's 6 elements and fails the second test but NIL if it's not 6 elements. You can use and and or instead of nesting ifs if more than one test needs to pass for something to be T. I would have used and here, like this:
(defun checkSongInfo (par1 par2)
(if (and (= 6 (length (nth par1 par2)))
(integerp (first (nth par1 par2))))
'complete
'incomplete))
This returns either complete if both tests passes and incomplete otherwise.

The else form is optional with if. Stylistically, if there is no else expression you'd use when.
(defun checkSongInfo (par1 par2)
(when (= 6 (length (nth par1 par2))) ; You're missing a ) here.
(if (intergerp (first (nth par1 par2)))
'complete
'incomplete))) ; Also missed a ) here.

Related

strange behaviour of (delete .. in Allegro Lisp

I try to remove random elements from a list until the list is empty. My environment is Allegro Lisp, free edition.
(setq set1 '(Nr1 Nr2 Nr3))
(delete (nth (random (length set1)) set1) set1)
After some repetitions, the output of sequential calls to delete (and the content of set1) start to look like this:
(NR1 NR2 NR3)
(NR2 NR3)
(NR1 NR2)
(NR1)
NIL
That is, sometimes items are not deleted, sometimes deleted items reappear. If I use remove there is no such problem.
Is this a bug or do I miss something about delete?
delete is allowed to destroy/mutate/reuse parts of the original list to return the result, this has two implications:
You should use (setf set1 (delete ...))
Mutating a quoted list is not a good idea, just use (setf set1 (list 'Nr1 'Nr2 'Nr3)) instead
When delete is asked to remove the first element of a list, it is allowed to simply return (cdr list), you need to (setf set1 (delete (nth (random (length set1)) set1)))

Cant use let variables in when condition [duplicate]

This question already has an answer here:
Lisp, instructions not working in defun [duplicate]
(1 answer)
Closed 8 months ago.
I have following code snippet:
(defun upsi()
(let ((firstpos (car *old-list*)) (secondpos (car(cdr *old-list*))))
(let ((found nil)(secondlocation (list (car (cdr firstpos)) (car secondpos))))
(when (= (found nil))
(setq *new-list* (list(firstlocation)))))))
This gives me following error "The function COMMON-LISP-USER::FOUND is undefined"
But when I try this code, it works perfectly.
(defun upsi()
(let ((firstpos (car *stenches*)) (secondpos (car(cdr *stenches*))))
(let ((found nil)(secondlocation (list (car (cdr firstpos)) (car secondpos))))
(print found)
(print secondlocation))))
What is the cause, that I cant use the variables found and secondlocation in my when condition. In fact I also cant use them in a loop. But when I print them I dont get any errors. It looks to me that they are out of scope but I dont understand why ?
I am just into common-lisp but this confuses me so much^^
Parentheses carry semantic meaning in Common Lisp, and you can't just place them anyplace you like as you can in many other languages. The first position of a list expression is interpreted as an identifier for a function, and that function is called on the arguments; this will fail when there is no such function.
In (when (= (found nil)) you are calling the function found, which doesn't exist. You probably meant (when (= found nil)), but this wouldn't work either because = is meant for comparing numbers in Common Lisp. You could use the null predicate, or it might be better to use an unless form instead of when.
The same problem also seems to occur in the body of the when form: (list (firstlocation)). Here the parentheses indicate that firstlocation is a function that you want to call. I don't think that this is the case given that secondlocation is a list, but I don't see firstlocation defined anyplace so I could be wrong.
A couple of other observations: there is a let* form that allows you to use identifiers which were previously bound in the same form. There is also cadr to use instead of calling car on the result of calling cdr, or you could use second. As presented here, your code is very difficult to read and reason about; you should really use an editor that properly indents your code, and look at some examples of lisp written by experienced programmers to get a feel for what it should look like.
Here are a couple of rewritten versions of your code; the first uses null and the second uses unless. I have assumed that firstlocation is a list, and just renamed secondlocation to firstlocation since secondlocation isn't used in the posted code for the sake of getting the code to function.
(defvar *old-list* '())
(defvar *new-list* '())
;; Using `let*`, `cadr`, and `when` with `null`:
(defun upsi()
(let* ((firstpos (car *old-list*))
(secondpos (car (cdr *old-list*))) ; could also use `cadr` or `second`
(found nil)
(firstlocation (list (cadr firstpos) (car secondpos))))
(when (null found)
(setq *new-list* (list firstlocation)))))
;; Using `let*`, `second`, and `unless`:
(defun upsi()
(let* ((firstpos (car *old-list*))
(secondpos (car (cdr *old-list*))) ; could also use `cadr` or `second`
(found nil)
(firstlocation (list (second firstpos) (car secondpos))))
(unless found
(setq *new-list* (list firstlocation)))))

How to read a racket code from a file, and execute the code

I want to define a function in racket that reads a racket code from an input file (for example "input.txt"), and runs the racket code and display the output. I tried doing this with the “read” function. But it only reads the first expression.
What you probably want is load. However it's mildly fiddly to get load to print the values of individual forms. Here is a simpler and probably not completely correct version of load which does this:
(define (load/print path
#:namespace (namespace (current-namespace))
#:printer (printer println)
#:suppress-void (suppress-void #t))
;; If the file starts with #lang &c this will let it be read, but the
;; printing won't generally be helpful in that case as it will be
;; read usually as a single (module ...) form.
(parameterize ([read-accept-reader #t]
[read-accept-lang #t])
(call-with-input-file
path
(λ (in)
(for ([form (in-port (λ (p) (read-syntax path p)) in)])
(call-with-values
(thunk (eval form namespace))
(λ vals
(for ([v (in-list vals)])
(unless (and suppress-void (void? v))
(printer v))))))
path))))
So given a file containing
1
(values 2 3 4)
"foo"
> (load/print "/path/to/my/file")
1
2
3
4
"foo"
"/tmp/file.rkt"

Modifying a list passed as a parameter gives different results in SBCL and CLISP

Can someone explain why I get different results for the following simple program with sbcl and clisp? Is what I am doing undefined by the language, or is one of the two lisp interpreters wrong?
; Modify the car of the passed-in list
(defun modify (a) (setf (car a) 123))
; Create a list and print car before and after calling modify
(defun testit () (let ((a '(0)))
(print (car a))
(modify a)
(print (car a))))
(testit)
SBCL (version 1.0.51) produces:
0
0
CLISP (version 2.49) produces (what I would expect):
0
123
I agree with Seth's and Vsevolod's comments in that this behavior is due to your modification of literal data. Try using (list 0) instead of '(0). Questions relating to this come up relatively frequently, so I'll quote the HyperSpec here.
3.7.1 Modification of Literal Objects:
The consequences are undefined if literal objects are destructively
modified.
The definition of "literal":
literal adj. (of an object) referenced directly in a program rather
than being computed by the program; that is, appearing as data in a
quote form, or, if the object is a self-evaluating object, appearing
as unquoted data. ``In the form (cons "one" '("two")), the expressions
"one", ("two"), and "two" are literal objects.''
Note that often (in many implementations), if you modify literal values, you'll really modify them in the code itself – writing self modifying code. Your example code will not work as you expect.
Your example code in CCL:
CL-USER> (defun modify (a) (setf (car a) 123))
MODIFY
CL-USER> (defun testit ()
(let ((a '(0)))
(print (car a))
(modify a)
(print (car a))))
TESTIT
CL-USER> (testit)
0
123
123
CL-USER> (testit)
123
123
123
Take a look at the second evaluation of testit, where the let itself really already contains the modified value, thus the first print also yields 123.
Also see: Lisp, cons and (number . number) difference, where I explained this in more detail, or the question linked in Vsevolod's comment above.

Statements not executing in order? (defvar within a let statement)

I've tried to reduce it to the minimal example. The code runs without an error, producing the expected output. But it gives me a warning that my first variable is undefined. It seems that the second statement of progn doesn't "see" the results of the first statement. Thanks for the help!
(I originally did not have the progn construct in the code at all, but after getting this error I added it to see if that would force execution in order -- but the error is the same.)
Here's the code:
(let ((input (open "input.lisp")))
(progn (defvar var1 (read input))
(defvar arr1 (make-array var1 :initial-contents (read input))))
(close input))
(print var1)
(print arr1)
These are the contents of the file "input.lisp":
9
(10 8 6 4 2 4 6 8 10)
And this is the output I get from sbcl after executing (load "test.lisp"):
; in: DEFVAR ARR1
; (MAKE-ARRAY VAR1 :INITIAL-CONTENTS (READ INPUT))
;
; caught WARNING:
; undefined variable: VAR1
;
; compilation unit finished
; Undefined variable:
; VAR1
; caught 1 WARNING condition
9
#(10 8 6 4 2 4 6 8 10)
T
So, it seems to me that both definition statements are executing, but the second doesn't "see" the results of the first. It still constructs the array correctly because it's filled with the given initial-contents. But why isn't var1 already defined?
See the documentation for defvar in the Hyperspec:
If a defvar or defparameter form appears as a top level form, the compiler must recognize that the name has been proclaimed special.
This implies (and it seems to be the case for SBCL) that if a defvar appears as a non-top-level form, then the compiler need not recognize that the name has been declared. So how come your defvars are not being compiled as top level forms? See section 3.2.3.1, Processing of Top Level Forms (point 6) for the answer: the let surrounding your code causes it to be compiled as non-top-level forms.
So you need to defvar your variables at top level, and then assign them later on with setf inside the let.
Like this. It's also usually simpler to use with-open-file rather than open and close.
(defvar var1)
(defvar arr1)
(with-open-file (input "input.lisp" :direction :input)
(setf var1 (read input))
(setf arr1 (make-array var1 :initial-contents (read input))))
(print var1)
(print arr1)
The reason that you are having this trouble is that you are placing your code at top level in the file. This is a slightly unusual thing to do: the normal Lisp coding style is to put most of your code in function definitions, and then to call those functions when you need to run them.
For example, this would be a more typical way to write this kind of code, with the initialization code in its own function.
(defvar *var1* nil "Documentation for var1.")
(defvar *arr1* nil "Documentation for arr1.")
(defun init-from-file (file)
"Read *var1* and *arr1* from file."
(with-open-file (input file :direction :input)
(setf *var1* (read input))
(setf *arr1* (make-array *var1* :initial-contents (read input)))))
(when (null *var1*) (init-from-file "input.lisp"))

Resources