Функция вызова Common Lisp

Я новичок в 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))))

Какова цель let привязки A?

coredump 30.09.2018 22:11
Что такое компоненты React? Введение в компоненты | Типы компонентов
Что такое компоненты React? Введение в компоненты | Типы компонентов
Компонент - это независимый, многократно используемый фрагмент кода, который делит пользовательский интерфейс на более мелкие части. Например, если мы...
0
1
820
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Вы близки, но в обоих определениях функций есть незначительные проблемы. В определении функции 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 )). Может стоит как-нибудь разобрать?

Lado 30.09.2018 19:52

Я обновил код в своем ответе, чтобы включить тест listp (поскольку вы рекурсивно вызываете my_eval, вам также необходимо проверить это, поскольку он будет передан спискам) и добавил действие mrg.

blihp 30.09.2018 20:12

Все, что находится после "((атом A) A)" было / уже предполагает, что A является списком (неявно, поскольку это не атом), поэтому добавление условия "(listp ..." сначала предотвращает любое из предложений от любого срабатывания - все возможные входы покрываются первыми двумя условиями.

Darren Ringer 30.09.2018 20:53

Спасибо за уловку @DarrenRinger ... поскольку другой ответ уже был принят, я просто удалил условие listp. Как вы правильно указали, он неправильно обходил остальную часть cond.

blihp 30.09.2018 22:00
Ответ принят как подходящий

Если смотреть на другие вызовы, условие для '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 ...), чтобы предотвратить дальнейшие осложнения.

Хорошо, я понял. Спасибо за ваше объяснение.

Lado 30.09.2018 21:36

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

Другие вопросы по теме