Макрос схемы — разверните список в набор вызовов функций

Эта процедура определения того, что ряд крестиков-ноликов помечен, не работает (строка X _ _ идентифицируется как полностью отмеченная, если это не так)

(define (won? b m)
  (define (row-marked? r)
    (every?-ec (:vector c (index i) b) (if (memv i r)) [char=? c m]))
  "Returns #t if the mark m won"
  (let ([rr '((0 1 2) (3 4 5) (6 7 8) (0 3 6) (1 4 7) (2 5 8) (0 4 8) (2 4 6))])
    `(or ,@(map (lambda (r) `(row-marked? (list ,@r))) rr))))

в то время как процедура ниже работает

(define (won? b m)
  (define (row-marked? r)
    (every?-ec (:vector c (index i) b) (if (memv i r)) [char=? c m]))
  "Returns #t if the mark m won"
  (or (row-marked? '(0 1 2)) (row-marked? '(3 4 5)) (row-marked? '(6 7 8))
      (row-marked? '(0 3 6)) (row-marked? '(1 4 7)) (row-marked? '(2 5 8))
      (row-marked? '(0 4 8)) (row-marked? '(2 4 6))))

Я пробовал безуспешно

(let ([rr '((0 1 2) (3 4 5) (6 7 8) (0 3 6) (1 4 7) (2 5 8) (0 4 8) (2 4 6))])
    `(or ,@(map (lambda (r) `(row-marked? ,r)) rr)))

и

(let ([rr '((0 1 2) (3 4 5) (6 7 8) (0 3 6) (1 4 7) (2 5 8) (0 4 8) (2 4 6))])
    `(or ,@(map (lambda (r) `(row-marked? ',r)) rr)))

также. Что я делаю неправильно?

Моя цель - избежать повторения кода и автоматически генерировать исполняемое выражение (or ...), сохраняя при этом короткое замыкание как or, так и every-ec.

Спасибо!

Какую схему вы используете?

Shawn 21.12.2020 02:29

я использую гош

Volodymyr Prokopyuk 21.12.2020 09:06

Это не макрос, это процедура, которая создает список '(or (row-marked ....

molbdnilo 21.12.2020 09:42

Есть ли способ сделать список исполняемым без использования eval? Моя цель - избежать повторения кода и автоматически генерировать исполняемое выражение (or ...), сохраняя при этом короткое замыкание как or, так и every-ec.

Volodymyr Prokopyuk 21.12.2020 10:12

Да, это можно сделать с помощью макроса.

molbdnilo 21.12.2020 10:54
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
Toor - Ангулярный шаблон для бронирования путешествий
Toor - Ангулярный шаблон для бронирования путешествий
Toor - Travel Booking Angular Template один из лучших Travel & Tour booking template in the world. 30+ валидированных HTML5 страниц, которые помогут...
0
5
89
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

То, что вам нужно, это не макрос (и, как вы указали, это не может быть сделано макросом), это SRFI 1 любая функция:

(define (won? b m)
  (define (row-marked? r)
    (every?-ec (:vector c (index i) b) (if (memv i r)) [char=? c m]))
  "Returns #t if the mark m won"
  (any row-marked?
       '((0 1 2) (3 4 5) (6 7 8) (0 3 6) (1 4 7) (2 5 8) (0 4 8) (2 4 6))))

Односписковая версия any, которая вам нужна, очень легко написать:

(define (any/1 p l)
  (if (null? l)
      #f
      (or (p (first l))
          (any/1 p (rest l)))))

Полноценный any немного сложнее сделать правильно, особенно если вы хотите, чтобы он был эффективным в простых случаях.


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

(let ([rr ...])
  (m row-marked? rr))

Тогда может ли m быть макросом, расширение которого равно (or (row-marked ...) ...)? Нет, не может быть, потому что макросы преобразуют исходный код, а список, привязанный к rr, недоступен до времени выполнения: у макроса нет исходного кода, который нужно преобразовать.

На самом деле, чего вы хотите избежать здесь, так это того, что формы в теле row-marked? должны оцениваться только столько раз, пока они не вернут true, и механизм для этого просто заключает их в функцию и вызывает только как много раз по мере необходимости.

Однако этот механизм иногда немного синтаксически неуклюж: если у меня есть что-то вроде

(any (λ (e1 e2)
       (and (integer? e1) (integer? e2)
            (even? e1) (even? e2))
            (not (= e1 e2)))
     l1 l2)

Я мог бы скорее написать это как

(finding-first ((e1 l1) (e2 l2))
  (and (integer? e1) (integer? e2)
       (even? e1) (even? e2)
       (not (= e1 e2))))

И, конечно же, вы можете:

(define-syntax finding-first
  (syntax-rules ()
    [(_ ((v l) ...) form ...)
     (any (λ (v ...) form ...) l ...)]))

Спасибо за ответ! Ответ решает проблему, поэтому я приму его, но в ответе не объясняется, как заставить работать код в вопросе. Я понимаю, что процедура в вопросе возвращает список '(or (row-marked? ..., но как этот список сделать исполняемым с помощью макроса — это еще вопрос.

Volodymyr Prokopyuk 21.12.2020 15:35

Я добавил дополнение, объясняющее, почему макрос не может быть использован здесь в любом полезном случае.

user5920214 21.12.2020 17:34

Большое спасибо за объяснение и за то, что вы подчеркнули тот факт, что существует большая разница между исходным кодом, который можно преобразовать с помощью макроса, и значениями переменных исходного кода во время выполнения, которые должны быть преобразованы с помощью процедур, а не макросов! Это действительно полезно и полезно! Спасибо, мужик!

Volodymyr Prokopyuk 22.12.2020 09:04

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