Общая функция вызова Lisp - PullRequest
       22

Общая функция вызова Lisp

0 голосов
/ 30 сентября 2018

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

Ответы [ 3 ]

0 голосов
/ 30 сентября 2018

Если посмотреть на другие вызовы, условие условия для '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 задаются в качестве аргументов для mrg funcall -call:

  • , а именно (cadr A) (что является синонимом (second A)) и
  • (caddr A) (что является синонимом (third A)).

Поскольку каждый из аргументов может быть атомом или другим вызовом функции или специальной формой, вы должны обернуть вокруг него вызов my_eval и оценить каждый из аргументов.

- Это, кстати, то, что всегда происходит, если вы вызываете функции Lisp - каждый аргумент (который является выражением) полностью вычисляется перед обработкой результата до вызова основной функции.

(Напротив, в вызовах макросов аргументы не оцениваются по умолчанию, как в вызовах функций. Вместо этого в теле функции вы имеете полный контроль над тем, когда каждый из аргументов будет оцениваться или обрабатываться как символ).

В своем комментарии к ответу @ blihp вы дважды цитировали A ('A) в форме let, и это препятствует тому, чтобы A принимали за список, которым он фактически соответствует.

Другая проблема, которую я вижу, заключается в том, что ваш my_eval не ищет quote, и я также не уверен, может ли ваша реализация my_eval, которая является очень элементарной, правильно обрабатывать '.Таким образом, в тестовом вызове mrg я рекомендую использовать (list 1 3 4 2 4 ...) вместо '(1 3 4 2 4 ...) для предотвращения дальнейших осложнений.

0 голосов
/ 02 октября 2018

Недопустимое количество аргументов: (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))))))
0 голосов
/ 30 сентября 2018

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

...