Я новичок в Common Lisp. И недавно начал его изучать. И у меня небольшая проблема, как вызвать одну функцию в другой? У меня есть функция mrg и функция my_eval. И как вызвать эту функцию mrg в my_eval, набрав, например, (print (my_eval '(mrg '(1 1 2 1 2 1 3) '(5 3 3 1 2 2)))). Я пробовал, но у меня были ошибки, такие как 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, но я не уверен, что вы хотели сделать в этом случае)
Я попробовал этот ((equal 'mrg (let ('A 'A)(funcall (A)(my_eval(cadr A)(merge 'list (sort A #'<) (sort A #'<) #'<)))))), но у меня возникла ошибка. И добавил этот ((equal 'mrg (funcall mrg ('A 'A)))) и выдала ошибку. И я не знаю, как назвать этот mrg в этой строке ((equal 'mrg )). Может стоит как-нибудь разобрать?
Я обновил код в своем ответе, чтобы включить тест listp (поскольку вы рекурсивно вызываете my_eval, вам также необходимо проверить это, поскольку он будет передан спискам) и добавил действие mrg.
Все, что находится после "((атом A) A)" было / уже предполагает, что A является списком (неявно, поскольку это не атом), поэтому добавление условия "(listp ..." сначала предотвращает любое из предложений от любого срабатывания - все возможные входы покрываются первыми двумя условиями.
Спасибо за уловку @DarrenRinger ... поскольку другой ответ уже был принят, я просто удалил условие listp. Как вы правильно указали, он неправильно обходил остальную часть cond.
Если смотреть на другие вызовы, условие для '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 применяется к первому элементу ist A (который является mrg), а затем два следующих элемента в списке A передаются в качестве аргументов для mrgfuncall -вызов:
(cadr A) (который является синонимом (second A)) и(caddr A) (синоним (third A)).Поскольку каждый из аргументов сам по себе может быть атомами или вызовами других функций или специальными формами, вы должны обернуть их вызов my_eval и оценить каждый из аргументов.
- Кстати, это всегда происходит, если вы вызываете функции Лиспа - каждый аргумент (который является выражением) полностью вычисляется для себя перед обработкой результата для вызова основной функции.
(Напротив, в вызовах макросов аргументы не оцениваются по умолчанию, как в вызовах функций. Вместо этого в теле функции вы имеете полный контроль над тем, когда каждый из аргументов будет оцениваться или обрабатываться как символ).
В своем комментарии к ответу @blihp вы дважды процитировали A ('A) в форме let, и это не позволяет использовать 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 параметра, но был вызван с 1 аргументом в (EQUAL MRG).
Заметьте также, что вы часто дублируете код.
Во всех случаях вы сравниваете заголовок списка с постоянным символом, а затем вызываете его, передавая ему в качестве аргументов результат вызова my_eval для первого, а иногда и для второго элемента того же списка.
По сути, ваш код делает это:
(apply (first list) (mapcar #'my-eval (rest list)))
Функция APPLY принимает обозначение функции и вызывает его с произвольным количеством аргументов. Здесь этот список аргументов является результатом применения my_eval к каждому оставшемуся элементу в списке.
Отличия от вашего кода:
(+ 1 4 9) будет оцениваться как 5 при my_eval). ИМХО, my_eval в этом случае скорее должен громко провалиться, потому что это, вероятно, не то, чего можно было бы ожидать.let, который повторно связывает A с именем локальной переменной A, здесь бесполезен.Если вы хотите сохранить этот подход, но удалить некоторое дублирование кода, вы можете попробовать это; следующая функция должна быть вызвана, если вы определили, что форма для оценки является cons-ячейкой.
(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))))))
Какова цель let привязки A?