Common Lisp генерирует имена переменных в макросе - PullRequest
2 голосов
/ 22 июня 2019

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

(defun straight-winner-p (board start size)
  (let ((row-player (aref board start 0))
        (row-count 0)
        (col-player (aref board 0 start))
        (col-count 0))

    (loop for step from 0 to (- size 1) do

         (if (equal
              (aref board start step)
              row-player)
             (incf row-count))
         (if (equal
              (aref board step start)
              col-player)
             (incf col-count))
         )
    (format t "row ~a, col ~a~%" row-count col-count)))

Вызов формата в конечном итоге будет заменен проверкой, равен ли игрок нулю и число равно размеру. Во всяком случае, я хотел заменить два ifs макросом. Итак, это было бы что-то вроде

(check row start step)

И макрос сгенерирует оператор if

         (if (equal
              (aref board start step)
              row-player)
             (incf row-count))

Затем вызовите тот же макрос с помощью (проверьте начало шага col). Я не могу заставить макрос генерировать счетчик строк и проигрыватель строк из строки. Как бы вы это сделали?

1 Ответ

3 голосов
/ 22 июня 2019

Как насчет использования функциональности в макросе цикла, когда вы уже используете макрос цикла:

(defun straight-winner-p (board start size)
  (loop :with row-player := (aref board start 0)
        :and col-player := (aref board 0 start)
        :for step :below size
        :count (equal (aref board start step) row-player) :into row-count
        :count (equal (aref board step start) col-player) :into col-count
        :finally (format t "row ~a, col ~a~%" row-count col-count)
                 (return (or (= row-count size) (= col-count size)))))

Как вы делаете то, что вы хотите:

(defmacro check (prefix start step)
  (let ((player (intern (concatenate 'string (string prefix) (string '-player)) (symbol-package prefix)))
        (count (intern (concatenate 'string (string prefix) (string '-count)) (symbol-package prefix))))
    `(when (equal (aref board ,start ,step) ,player)
       (incf ,count))))

Хотя особое внимание было уделено тому, что макрос и ваш код оказываются в разных пакетах и ​​используют пакет с предоставленным символом, он не будет работать, если файлы считываются с другими настройками считывателя. Если вы скомпилируете один, но не другой, он может не сработать.

...