【问题标题】:Lisp function returns NIL when used in a menu function but otherwise worksLisp 函数在菜单函数中使用时返回 NIL,但在其他情况下有效
【发布时间】:2020-02-05 01:13:58
【问题描述】:

我编写了一个函数来查询我正在为学校编写的小型数据库程序。此函数按名称搜索。当我自己运行该功能时,它可以工作。当我在菜单中运行它时它不起作用(它返回 NIL)。 以下是所有相关内容:

(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                                                                          
)  

现在我只致力于让名称搜索正常工作,菜单的其余部分只是占位符。当我自己运行“输入名称”(使用搜索名称)时,它会返回正确的结果。当我尝试搜索菜单中的第一个选项(也运行“输入名称”)时,它返回 NIL。我想知道为什么当我单独运行它时它会起作用,但与该菜单一起使用时却不起作用。如果有人需要任何其他信息,请随时询问。我会尽力提供。另外,我是初学者,请见谅。

【问题讨论】:

  • 我不明白这个问题。您可能需要向我们展示互动。就像函数search-menu 当前一样,它总是返回NIL,因为这是代码中明确显示的最后一个值——参见search-menu 的倒数第二行。除了NIL,它怎么能返回任何东西?
  • 另外:变量choose 在您的代码中未定义。 setf 不定义变量 - 它只设置它们。
  • 提示:尝试理解在函数中打印一些东西、从函数中返回值和打印评估结果之间的区别在 READ-EVEL-PRINT-LOOP 中.

标签: lisp common-lisp clisp slime abcl


【解决方案1】:

如果你想在程序中输出,那么你需要打印一些东西。

(defun example ()
  1000)

上述函数不打印任何内容。它只是返回一个数字。

如果我们在 read-eval-print-loop 中调用它:

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

CL-USER 135 > (example)
1000

您看到打印了 1000。但为什么呢?

我们在 READ-EVAL-PRINT-LOOP 中运行它。读取、评估、PRINT、循环。

意味着:Lisp 系统正在打印评估的返回值,而不是您的代码。

现在我们添加一个 print 调用:

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

CL-USER 137 > (example)

1000 
1000

打印了两次!

CL-USER 137 > (example)

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

所以我们的函数现在自己打印一些东西,因为它调用了PRINT。

现在可以了:

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

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

1000 

我们可以调用example函数,函数打印一些东西,而REPL什么也不打印。

REPL 不打印任何内容,因为 call-the-example 不返回任何内容。它不返回任何值。

因此您需要添加一个 PRINT 调用

添加打印调用是对的,但原因很简单,因为在您没有打印之前,对(input-name) 的调用没有打印。您在 READ-EVAL-PRINT-LOOP 中调用 (input-name),然后打印结果。不是您的代码,而是 REPL 确实输出了。

样式:未定义变量

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

改为使用 LET 定义局部变量:

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

【讨论】:

    【解决方案2】:

    search-menu 不会对来自input-name 的返回值做任何事情。函数返回它执行的最后一个表达式的值,而search-menu 中的最后一个表达式是NIL,所以它返回的就是这个。

    如果您希望它返回 cond 表达式的值,请从末尾删除 NIL。

    您还应该使用let 来声明一个局部变量,而不是分配未定义的变量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")))))
    

    【讨论】:

      【解决方案3】:

      我最终找到了一个解决方案,只需在 input-name 函数中使用 print 即可。这个函数只需要显示结果就可以了。

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

      与以前的功能相同,但增加了打印。现在它也可以在菜单中使用。

      【讨论】:

      • 但是现在当你自己运行这个函数时,结果会被打印两次。你明白为什么吗?
      • @RainerJoswig 是的,不过没关系。这只是一个初学者项目,我所要做的就是在屏幕上显示正确的结果。
      • 问题是:你明白它为什么要打印两次吗?
      • 我说“是的”。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-15
      • 1970-01-01
      相关资源
      最近更新 更多