Common Lisp调用函数
Common Lisp call function
我是 Common Lisp 的新手。最近开始学习它。我有一个小问题,如何在另一个函数中调用一个函数?我有函数 mrg
和函数 my_eval
。以及如何通过键入 (print (my_eval '(mrg '(1 1 2 1 2 1 3) '(5 3 3 1 2 2))))
在 my_eval
中调用此函数 mrg
。我试过了,但出现了一些错误,例如 it's not a real number
或 undefined 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))))
你很接近,但两个函数定义都有小问题。在mrg函数定义中,需要在函数声明后传递一个形式(即括号内要执行的内容):
(defun mrg (w v)
(merge 'list (sort w #'<) (sort v #'<) #'<))
并且您的 my_eval 函数对于 mrg 条件不完整:
(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 测试的操作(即另一种形式),但我不确定您在这种情况下想要做什么)
如果查看其他调用,'mrg 的条件子句必须是
((equal 'mrg (car A)) (let ((A A)) (funcall (car A) (my_eval (cadr A)) (my_eval (caddr A)))))
A
必须是一个列表,因为它在第一个 cond
子句 (atom A)
.
中失败
由于 mrg
在此实现中需要两个参数,
就像在这个 eval 中一样,内置函数
`cons`
`list`
`equal`
`*`
`/`
`+`
`-`
`=`
也一样,
在将列表 A
复制到局部符号 A
((let ((A A)) ...)
部分)后,funcall
应用于列表 A
的第一个元素(即mrg
),然后列表 A
中的以下两个元素作为 mrg
funcall
调用的参数:
- 即
(cadr A)
((second A)
的同义词)和
(caddr A)
((third A)
的同义词)。
由于每个参数本身都可以是原子或其他函数调用或特殊形式,因此您必须围绕它们进行 my_eval
调用并评估每个参数。
-- 顺便说一下,如果你调用 Lisp 函数,这就是经常发生的事情——每个参数(它是一个表达式)在将结果传递给主函数调用之前都会对其自身进行完全评估。
(相比之下,在宏调用中,参数不会像在函数调用中那样默认计算。相反,您可以在函数体中完全控制何时计算每个参数或将其视为符号)。
在您对@blihp 的回答的评论中,您在 let
形式中引用了 A ('A
) 两次,这阻止了 A 被视为它实际代表的列表。
我看到的另一个问题是你的 my_eval
没有寻找 quote
而且我也不确定你的 my_eval
实现是否是一个非常基本的实现,可以处理'
正确。因此在测试 mrg
调用中,我建议使用 (list 1 3 4 2 4 ...)
而不是 '(1 3 4 2 4 ...)
以防止进一步的并发症。
Invalid number of arguments: (EQUAL MRG)
正如其他答案所指出的,存在一个参数不匹配:EQUAL
接受 2 个参数但在 (EQUAL MRG)
中使用 1 个参数调用。
另请注意,您经常重复代码。
在所有情况下,您将列表的头部与常量符号进行比较,然后通过将调用 my_eval
的结果作为参数作为参数来调用它,有时是第二个元素相同的列表。
基本上,您的代码是这样做的:
(apply (first list) (mapcar #'my-eval (rest list)))
APPLY
函数采用 函数指示符 并使用任意数量的参数调用它。在这里,参数列表是将 my_eval
应用于列表中每个剩余元素的结果。
与您的代码的不同之处在于:
- 每个功能都在head位置检查,有利于安全,可以用授权符号列表复制。
- 您丢弃剩余的参数,如果它们存在(例如
(+ 1 4 9)
将在 my_eval
下计算为 5)。恕我直言,my_eval
在那种情况下宁愿大声失败,因为这可能不是任何人所期望的。
- 另请注意,将
A
重新绑定到局部变量名称 A
的 let
在这里没有用。
如果您想保留该方法但要删除一些重复代码,您可以试试这个;应调用以下函数,您确定要评估的形式是一个cons-cell。
(defun my-eval/apply (cons)
(check-type cons cons)
(destructuring-bind (head . tail) cons
(let ((size (length tail))
(arity (case head
((car cdr atom) 1)
((cons list equal * / + - = mrg) 2))))
(cond
((not arity) (error "Unknown function ~a" head))
((= size arity) (apply head (mapcar #'my_eval tail)))
(t (error
"Arity mismatch: ~a takes ~d parameter~:p but was ~
called with ~d argument~:p in ~s" head arity size cons))))))
我是 Common Lisp 的新手。最近开始学习它。我有一个小问题,如何在另一个函数中调用一个函数?我有函数 mrg
和函数 my_eval
。以及如何通过键入 (print (my_eval '(mrg '(1 1 2 1 2 1 3) '(5 3 3 1 2 2))))
在 my_eval
中调用此函数 mrg
。我试过了,但出现了一些错误,例如 it's not a real number
或 undefined 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))))
你很接近,但两个函数定义都有小问题。在mrg函数定义中,需要在函数声明后传递一个形式(即括号内要执行的内容):
(defun mrg (w v)
(merge 'list (sort w #'<) (sort v #'<) #'<))
并且您的 my_eval 函数对于 mrg 条件不完整:
(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 测试的操作(即另一种形式),但我不确定您在这种情况下想要做什么)
如果查看其他调用,'mrg 的条件子句必须是
((equal 'mrg (car A)) (let ((A A)) (funcall (car A) (my_eval (cadr A)) (my_eval (caddr A)))))
A
必须是一个列表,因为它在第一个 cond
子句 (atom A)
.
由于 mrg
在此实现中需要两个参数,
就像在这个 eval 中一样,内置函数
`cons`
`list`
`equal`
`*`
`/`
`+`
`-`
`=`
也一样,
在将列表 A
复制到局部符号 A
((let ((A A)) ...)
部分)后,funcall
应用于列表 A
的第一个元素(即mrg
),然后列表 A
中的以下两个元素作为 mrg
funcall
调用的参数:
- 即
(cadr A)
((second A)
的同义词)和 (caddr A)
((third A)
的同义词)。
由于每个参数本身都可以是原子或其他函数调用或特殊形式,因此您必须围绕它们进行 my_eval
调用并评估每个参数。
-- 顺便说一下,如果你调用 Lisp 函数,这就是经常发生的事情——每个参数(它是一个表达式)在将结果传递给主函数调用之前都会对其自身进行完全评估。
(相比之下,在宏调用中,参数不会像在函数调用中那样默认计算。相反,您可以在函数体中完全控制何时计算每个参数或将其视为符号)。
在您对@blihp 的回答的评论中,您在 let
形式中引用了 A ('A
) 两次,这阻止了 A 被视为它实际代表的列表。
我看到的另一个问题是你的 my_eval
没有寻找 quote
而且我也不确定你的 my_eval
实现是否是一个非常基本的实现,可以处理'
正确。因此在测试 mrg
调用中,我建议使用 (list 1 3 4 2 4 ...)
而不是 '(1 3 4 2 4 ...)
以防止进一步的并发症。
Invalid number of arguments: (EQUAL MRG)
正如其他答案所指出的,存在一个参数不匹配:EQUAL
接受 2 个参数但在 (EQUAL MRG)
中使用 1 个参数调用。
另请注意,您经常重复代码。
在所有情况下,您将列表的头部与常量符号进行比较,然后通过将调用 my_eval
的结果作为参数作为参数来调用它,有时是第二个元素相同的列表。
基本上,您的代码是这样做的:
(apply (first list) (mapcar #'my-eval (rest list)))
APPLY
函数采用 函数指示符 并使用任意数量的参数调用它。在这里,参数列表是将 my_eval
应用于列表中每个剩余元素的结果。
与您的代码的不同之处在于:
- 每个功能都在head位置检查,有利于安全,可以用授权符号列表复制。
- 您丢弃剩余的参数,如果它们存在(例如
(+ 1 4 9)
将在my_eval
下计算为 5)。恕我直言,my_eval
在那种情况下宁愿大声失败,因为这可能不是任何人所期望的。 - 另请注意,将
A
重新绑定到局部变量名称A
的let
在这里没有用。
如果您想保留该方法但要删除一些重复代码,您可以试试这个;应调用以下函数,您确定要评估的形式是一个cons-cell。
(defun my-eval/apply (cons)
(check-type cons cons)
(destructuring-bind (head . tail) cons
(let ((size (length tail))
(arity (case head
((car cdr atom) 1)
((cons list equal * / + - = mrg) 2))))
(cond
((not arity) (error "Unknown function ~a" head))
((= size arity) (apply head (mapcar #'my_eval tail)))
(t (error
"Arity mismatch: ~a takes ~d parameter~:p but was ~
called with ~d argument~:p in ~s" head arity size cons))))))