首页 > 解决方案 > 使用 () 参数调用的未定义函数

问题描述

我正在处理这个问题。如果满足以下条件,我正在编写一个返回 true 的函数。输入是一个列表,有两个有效的操作:foo 和 baz

(foo a b c ... ) 

是有效的,所以以 foo 开头后跟字母或数字的列表是有效的,只要你想要。

(baz a) 

所以baz后面跟单词字母、数字都是有效的。我也可以将它们组合起来:

(foo (baz a) b 42 hello) it is valid 

(baz (foo a hello 42)) it is valid

仅包含一个元素的列表也是有效的:(a) (hello) (42)

如果我使用其他运算符,则无效:例如

(pizza a b c)或者(foo (dog a b) a)

所以每个括号的第一个元素必须是有效的运算符


(defun ok-operation (x)
  (cond ((eq (car x) 'foo) (ok-list (cdr x)) T)
        ((eq (car x) 'baz) (ok-list (cdr x) T))))

(defun ok-list (x)
  (cond ((atom (car x)) (ok-list (cdr x)) T)
        (t (ok-operation (cdr x) )))

最常见的错误是:

未定义的函数列表调用参数()

变量原子未绑定

标签: listlispcommon-lisp

解决方案


从这个问题中我不太清楚你所追求的实际语义是什么。然而,这是我非常喜欢的这种递归下降问题的一种解决方案的实现(几乎肯定不适合作为家庭作业的答案!)。弄清楚在更流行的对象系统中做这样的事情有多难,这有点有趣。

作为对了解 CLOS 的人的说明:我倾向于将琐碎或琐碎的默认情况下的方法放在defgeneric表单中:这可能不是通常的样式,但我喜欢它,因为这意味着您可以看到所有您从未见过的简单情况通用函数定义的更改,您不太可能忽略一些关键的后备案例。

附加价值:此代码中的错误是什么,您如何修复它?

(defgeneric form-ok-p (form)
  ;; This is the entry point
  (:documentation
   "Is a form OK?")
  (:method ((form number))
   ;; numbers are OK
   t)
  (:method ((form symbol))
   ;; symbols are OK
   ;;
   ;; This seems to be the case from the example but the text says
   ;; 'letters' which would more naturally mean strings or perhaps
   ;; characters.  So, well, this might need to be made more complicated.
   ;; Note this means that (form-ok-p '()) is true.
   t)
  (:method ((form t))
   ;; defaultly forms are not OK
   nil))

    (defmethod form-ok-p ((form cons))
  ;; a cons is OK if it is OK as an operator with arguments
  (destructuring-bind (operator . args) form
    (and (listp args)
         ;; check the arguments are a proper list (this could also be
         ;; done in an around method on operator-ok-p and that might
         ;; be cooler).  This considers that if ARGS is not a proper
         ;; list then the form is not OK, but isn't an error: it might
         ;; be appropriate to actually consider this case an error, so
         ;; (form-ok-p '(foo . a)) would raise an error.  (The
         ;; deficiency in this code is here).
         (loop for tail on args
               unless (or (null tail) (consp tail))
               do (return nil)
               finally (return t))
         (operator-ok-p operator args))))

(defgeneric operator-ok-p (op args)
  ;; Methods on this GF can assume that ARGS is a proper list
  (:documentation
   "Is an operator with some arguments OK?")
  (:method (op args)
   ;; defaultly, no it's not
   nil))

(defmethod operator-ok-p ((op (eql 'foo)) args)
  ;; (foo ...) is OK if all its args are OK
  (every #'form-ok-p args))

(defmethod operator-ok-p ((op (eql 'bar)) args)
  ;; (bar ...) is OK if there is one arg and it's OK
  (and (null (rest args))
       (form-ok-p (first args))))

推荐阅读