Общая функция не может найти подходящий метод

Когда я вызываю (draw win), я получаю сообщение об ошибке: «Общая функция не может найти применимый метод. Я только что попал в CLOS и использую sdl2kit, чтобы просто отобразить окно.

(defclass game-window (kit.sdl2:window)
  ((rotation :initform 0.0)))

(defmethod render ((win game-window))
 (with-slots (rotation) win
 (gl:load-identity)
 (gl:rotate rotation 0 0 1)
 (gl:clear-color 0.0 0.0 1.0 1.0)
 (gl:clear :color-buffer)
 (gl:begin :triangles)
 (gl:color 1.0 0.0 0.0)
 (gl:vertex 0.0 1.0)
 (gl:vertex -1.0 -1.0)
 (gl:vertex 1.0 -1.0)
 (gl:end)))
(defgeneric draw(win)
 (:documentation "draw window"))
(defun main ()
 (let (( win (make-instance 'game-window)))
  (draw win)))

person ZhangBing    schedule 17.02.2017    source источник
comment
В коде есть только определение универсальной функции, но она ничего не делает сама по себе. Вам также необходимо определить метод, специализирующийся на GAME-WINDOW. См., например, Practical Common Lisp Chapter 16.   -  person jkiiski    schedule 17.02.2017
comment
Я уже прочитал эту страницу, но мне все еще трудно понять примеры из книги. Я думал, что defgeneric вызовет метод в соответствии со специалистом. Я думал, что мой метод рендеринга уже имеет игровое окно, специализирующееся на выигрыше с рендерингом ((win game-window)).   -  person ZhangBing    schedule 17.02.2017
comment
Я думал, что в моем методе рендеринга уже есть игровое окно, специализирующееся на win with render ((win game-window)). Вы не путаете draw с render? Вы определили метод для render, но не для draw.   -  person coredump    schedule 17.02.2017
comment
DEFGENERIC ничего не вызывает. Он определяет общую функцию, в данном случае с именем DRAW, которую можно специализировать для различных типов аргументов путем определения методов (так же, как метод, который у вас есть для RENDER).   -  person jkiiski    schedule 17.02.2017
comment
О, значит, у них должно быть одно и то же имя? Итак, я должен сделать функцию рендеринга defgeneric? Я думал, что общие функции и методы не могут иметь одно и то же имя, поэтому я запутался.   -  person ZhangBing    schedule 17.02.2017
comment
DEFMETHOD создает общую функцию, если ее нет. Вы всегда можете использовать DEFGENERIC, чтобы указать дополнительные параметры. Но в вашем примере должно быть очевидно, что DRAW ничего не делает, так как у него нет кода...   -  person Rainer Joswig    schedule 17.02.2017
comment
Да, и я думал, что единственная цель универсальных функций - использовать их для вызова метода, но @jkiiski сказал, что универсальные функции ничего не вызывают. Я рассмотрю указанный вариант. Извините, я новичок в lisp, и вся концепция универсальных функций меня действительно смутила, потому что я не уверен, что универсальные функции делают под капотом или нет. Если бы DRAW был DEFUN, я бы понял, что он ничего не сделает, потому что у них нет кода.   -  person ZhangBing    schedule 17.02.2017
comment
Просто: одна общая функция может быть специализирована различными методами. Каждый метод назван так же, как и универсальная функция, но он отличается от других методов универсальной функции благодаря своим специализаторам (типам аргументов) и квалификаторам (вокруг, перед , после, ...). Теперь, когда вы запускаете defmethod без предыдущего defgeneric, универсальная функция определяется автоматически.   -  person coredump    schedule 17.02.2017


Ответы (1)


Итак, есть две проблемы. Одна из них связана с английским языком (вы должны быть очень осторожны, потому что каждое английское слово перегружено множеством значений программирования. Например, когда вы пишете «позвонить», неясно, имеете ли вы в виду «имя» или «вызвать/применить».) но это не имеет большого значения

Другая проблема заключается в том, что вы не знаете, что такое универсальная функция. Вот краткое объяснение.

Общая функция состоит (примерно) из трех частей:

  1. Лямбда-список
  2. Комбинация методов
  3. Набор методов

Метод состоит из трех частей

  1. Специализированный лямбда-список
  2. Некоторый код
  3. Что-то, связанное с комбинацией методов (обычно nil)

Когда вы вызываете общую функцию, это происходит:

  1. Он смотрит на типы аргументов
  2. Для упорядочения методов по специфичности применяются различные правила.
  3. Комбинация методов говорит, как объединить их в функцию
  4. Генерируется и компилируется код комбинированной функции.
  5. Сгенерированная функция вызывается с аргументами.

Шаги 2-4 обычно кэшируются.

Шаг 3 представлен примерно в двух формах:

  1. Standard method combination:
    1. All around methods are called
    2. Затем все before методы
    3. Вызывается наиболее конкретный метод (с соответствующей цепочкой методов, настроенных для call-next-method)
    4. Затем все after методы
    5. Результат возвращается через все around методы
  2. Другие комбинации методов обычно применяют все результаты методов к некоторому оператору, например and, progn или append.

Чтобы добавить метод в набор методов универсальной функции, обычно используется defmethod с тем же именем, что и у универсальной функции.

person Dan Robertson    schedule 24.07.2018