通用Lisp通话功能

时间:2018-09-30 17:00:05

标签: function common-lisp eval

我是Common Lisp的新手。并且最近开始学习它。我有一个小问题,如何在另一个函数中调用一个函数?我有一个函数mrg和一个函数my_eval。以及如何通过键入例如mrgmy_eval中调用此函数(print (my_eval '(mrg '(1 1 2 1 2 1 3) '(5 3 3 1 2 2))))。我尝试过,但是遇到了一些错误,例如it's not a real numberundefined function A。请帮助我。

这是我的代码:

(defun mrg (w v)
  (merge 'list (sort w #'<) (sort v #'<) #'<))

(defun my_eval (A)
  (cond
    ((atom A) A)
    ((equal 'car (car A))
     (let ((A A)) (funcall (car A) (my_eval (cadr A)))))
    ((equal 'cdr (car A))
     (let ((A A)) (funcall (car A) (my_eval (cadr A)))))
    ((equal 'atom (car A))
     (let ((A A)) (funcall (car A) (my_eval (cadr A)))))
    ((equal 'cons (car A))
     (let ((A A)) (funcall (car A) (my_eval (cadr A)) (my_eval (caddr A)))))
    ((equal 'list (car A))
     (let ((A A)) (funcall (car A) (my_eval (cadr A)) (my_eval (caddr A)))))
    ((equal 'equal (car A))
     (let ((A A)) (funcall (car A) (my_eval (cadr A)) (my_eval (caddr A)))))
    ((equal '* (car A))
     (let ((A A)) (funcall (car A) (my_eval (cadr A)) (my_eval (caddr A)))))
    ((equal '/ (car A))
     (let ((A A)) (funcall (car A) (my_eval (cadr A)) (my_eval (caddr A)))))
    ((equal '+ (car A))
     (let ((A A)) (funcall (car A) (my_eval (cadr A)) (my_eval (caddr A)))))
    ((equal '- (car A))
     (let ((A A)) (funcall (car A) (my_eval (cadr A)) (my_eval (caddr A)))))
    ((equal '= (car A))
     (let ((A A)) (funcall (car A) (my_eval (cadr A)) (my_eval (caddr A)))))
    ((equal 'mrg    ))
    (T A)))

(print (my_eval '(mrg '(1 1 2 1 2 1 3) '(5 3 3 1 2 2))))

3 个答案:

答案 0 :(得分:1)

您已经关闭,但是两个函数定义都存在较小的问题。在mrg函数定义中,您需要在函数声明后传递一个表单(即,要执行的操作用括号括起来):

(defun mrg (w v)
    (merge 'list (sort w #'<) (sort v #'<) #'<))

对于mrg条件,您的my_eval函数不完整:

(defun my_eval(A)
    (cond
        ((atom A) A)
        ((equal 'car    (car A)) (let ((A A)) (funcall (car A) (my_eval (cadr A)))))
        ((equal 'cdr    (car A)) (let ((A A)) (funcall (car A) (my_eval (cadr A)))))
        ((equal 'atom   (car A)) (let ((A A)) (funcall (car A) (my_eval (cadr A)))))
        ((equal 'cons   (car A)) (let ((A A)) (funcall (car A) (my_eval (cadr A)) (my_eval (caddr A)))))
        ((equal 'list   (car A)) (let ((A A)) (funcall (car A) (my_eval (cadr A)) (my_eval (caddr A)))))
        ((equal 'equal  (car A)) (let ((A A)) (funcall (car A) (my_eval (cadr A)) (my_eval (caddr A)))))
        ((equal '*      (car A)) (let ((A A)) (funcall (car A) (my_eval (cadr A)) (my_eval (caddr A)))))
        ((equal '/      (car A)) (let ((A A)) (funcall (car A) (my_eval (cadr A)) (my_eval (caddr A)))))
        ((equal '+      (car A)) (let ((A A)) (funcall (car A) (my_eval (cadr A)) (my_eval (caddr A)))))
        ((equal '-      (car A)) (let ((A A)) (funcall (car A) (my_eval (cadr A)) (my_eval (caddr A)))))
        ((equal '=      (car A)) (let ((A A)) (funcall (car A) (my_eval (cadr A)) (my_eval (caddr A)))))
        ((equal 'mrg    (car A)) (let ((A A)) (funcall (car A) (my_eval (cadr A)) (merge 'list (sort A #'<) (sort A #'<) #'<))))
        (T A)
    )
) 

(看起来您仍然缺少mrg测试的操作(即另一种形式),但我不确定在这种情况下您想做什么)

答案 1 :(得分:1)

如果要查看其他调用,则'mrg的条件子句必须为

A

cond必须是列表,因为它在第一个(atom A)子句mrg中失败。

由于`cons` `list` `equal` `*` `/` `+` `-` `=` 在此实现中需要两个参数, 就像本评估中的内置函数

A

也可以, 将列表A复制到本地符号(let ((A A)) ...)funcall部分)后,A应用于ist mrg的第一个元素(即A),然后将列表mrg中的以下两个元素作为funcall (cadr A)调用的参数:

  • 分别为(second A)(与(caddr A)的同义词)和
  • (third A)(是my_eval的同义词)。

由于每个参数本身都可以是原子或其他函数调用或特殊形式,因此必须在它们周围包装一个'A调用并评估每个参数。

-这是在调用Lisp函数时经常发生的情况-在处理结果到主函数调用之前,每个参数(它是一个表达式)都将被完全求值。

(相反,在宏调用中,默认情况下不会像在函数调用中那样对参数进行求值。相反,您可以在函数体内完全控制何时将每个参数作为符号进行求值或将其视为符号)

在对@blihp答案的评论中,您以let形式两次引用了A(my_eval),这阻止了A被视为其实际代表的列表。

我看到的另一个问题是您的quote找不到my_eval,而且我也不确定您的'实现(这是非常基本的实现)是否可以处理{{ 1}}正确。因此,在测试mrg中,我建议使用(list 1 3 4 2 4 ...)而不是'(1 3 4 2 4 ...)来防止进一步的并发症。

答案 2 :(得分:0)

  

无效数量的参数:(EQUAL MRG)

正如其他答案所指出的,存在Arity匹配:EQUAL带有2个参数,但是在(EQUAL MRG)中有1个参数被调用。

还请注意,您正在重复很多代码。

在所有情况下,您都将列表的开头与常量符号进行比较,然后通过将my_eval调用同一对象的第一个元素(有时是第二个元素)的结果作为参数来对其进行有趣的调用清单。 基本上,您的代码正在执行此操作:

(apply (first list) (mapcar #'my-eval (rest list)))

APPLY函数带有一个函数指示符,并使用任意数量的参数进行调用。在这里,该参数列表是对列表中其余的每个元素应用my_eval的结果。

与您的代码的区别是:

  • 您可以在头部位置检查每个功能,这对安全性有好处,并且可以与授权符号列表一起复制。
  • 如果剩余参数存在,则您将其丢弃(例如(+ 1 4 9)my_eval下的值为5。恕我直言,my_eval在这种情况下应该大声失败,因为这可能不是任何人所期望的。
  • 请注意,将let重新绑定到本地变量名称A的{​​{1}}在这里没有用。

如果您想保留该方法但要删除一些重复的代码,则可以尝试此方法;您应该确定要评估的表单是cons单元格,然后调用以下函数。

A