Lisp function returns NIL when used in a menu function but otherwise works

516 views Asked by At

I wrote a function to query a small database program I'm writing for school. This function searches by name. When I run the function by itself it works. When I run it within the menu it does not work (it returns NIL). Here is everything relevant:

(defun prompt-read (prompt)                                                    
  (format *query-io* "~a: " prompt)                                            
  (force-output *query-io*)                                                    
  (read-line *query-io*)) 

(defun search-name (name)                                                      
  (remove-if-not                                                               
   #'(lambda (cat) (equal (getf cat :name) name)) *db*))                       

(defun input-name ()                                                           
  (search-name                                                                 
   (prompt-read "Name")))

(defun search-menu ()                                                          
  (print "1) Search Name")                                                     
  (print "2) Search Color")                                                    
  (print "3) Search Min. Weight")                                              
  (print "4) Search Min. Experience")                                          
  (print "5) Search Min. Length")                                              
  (setf choose (read))                                                         
  (cond ((= choose 1)(input-name))                                             
        ((= choose 2)(print "Color"))                                          
        ((= choose 3)(print "Weight"))                                         
        ((= choose 4)(print "XP"))                                             
        ((= choose 5)(print "Color"))                                          
  )                                                                            
  NIL                                                                          
)  

Right now I am only working on getting the name search working, the rest of the menu is just placeholders. When I run "input-name" (which uses search-name) by itself it returns the correct result. When I try the first option from the search-menu (which also runs "input-name") it returns NIL. I am wondering why when I run it by itself works but not when used with that menu. If anybody needs any other information feel free to ask. I will try my best to provide it. Also, I am a beginner so please forgive me.

3

There are 3 answers

0
Rainer Joswig On

If you want output in a program, then you need to print something.

(defun example ()
  1000)

The above function prints nothing. It just returns a number.

If we call it in the read-eval-print-loop:

CL-USER 134 > (defun example ()
                1000)
EXAMPLE

CL-USER 135 > (example)
1000

You see that 1000 gets printed. But why?

We run it in the READ-EVAL-PRINT-LOOP. The read, eval, PRINT, loop.

Means: the Lisp system is printing the returned value of the evaluation, but not your code.

Now we add a print call:

CL-USER 136 > (defun example ()
                (print 1000))
EXAMPLE

CL-USER 137 > (example)

1000 
1000

It's printed twice!

CL-USER 137 > (example)

1000     ; <- the function example prints 
1000     ; <- the read-eval-print-loop prints the result

So our function now prints something itself, since it calls PRINT.

Now this works:

CL-USER 138 > (defun call-the-example ()
                (example)
                (values))
CALL-THE-EXAMPLE

CL-USER 139 > (call-the-example)

1000 

We can call the example function, the function prints something, and the REPL prints nothing.

The REPL prints nothing, since call-the-example returns nothing. It returns no value.

Thus you need to add a PRINT call

You are right to add a print call, but the reason is simply that before you did not print and the call to (input-name) did not print. You were calling (input-name) in the READ-EVAL-PRINT-LOOP, which then prints the result. Not your code, but the REPL did output.

Style: undefined variable

(defun foo ()
  (setf bar 10)  ; <- BAR is undefined
  (print bar)    ; <- BAR is undefined
  (setf bar 20)  ; <- BAR is undefined
  (print bar))   ; <- BAR is undefined

Write this instead - using LET to define a local variable:

(defun foo ()
  (let ((bar 10))    ; define BAR
    (print bar)      ; BAR is defined
    (setf bar 20)    ; BAR is defined
    (print bar)))    ; BAR is defined
4
kokko1G On

I ended up finding a solution that works by simply using print in the input-name function. This function only has to show results so this works just fine.

(defun input-name ()                                                           
  (print                                                                       
  (search-name                                                                 
   (prompt-read "Name")))) 

Same function as before but with an added print. Now it also works in the menu.

0
Barmar On

search-menu doesn't do anything with the return value from input-name. A function returns the value of the last expression that it executes, and the last expression in search-menu is NIL, so that's what it returns.

If you want it to return the value of the cond expression, remove NIL from the end.

You should also use let to declare a local variable, rather than assigning the undefined variable choose.

(defun search-menu ()
  (print "1) Search Name")
  (print "2) Search Color")
  (print "3) Search Min. Weight")
  (print "4) Search Min. Experience")
  (print "5) Search Min. Length")
  (let ((choose (read)))
    (cond ((= choose 1) (input-name))
          ((= choose 2) (print "Color"))
          ((= choose 3) (print "Weight"))
          ((= choose 4) (print "XP"))
          ((= choose 5) (print "Color")))))