方案宏 - 将列表扩展为一组函数调用

Scheme macro - Expand a list into a set of function calls

此识别井字游戏行是否已标记的过程不起作用(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 ...) 表达式,同时保持 orevery-ec

的短路

谢谢!

您需要的不是宏(正如您指定的那样,宏无法完成),而是 SRFI 1's any 函数:

(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 ...) ...)的宏吗?不,不可能,因为宏转换 source code 并且绑定到 rr 的列表在 运行 之前不可用:宏不有它需要转换的源代码。

真的,你想在这里避免的事情是 row-marked? 正文中的形式应该只被计算多次,直到它们 return 为真,以及这样做的机制只是将它们包装在一个函数中,并根据需要多次调用它。

然而,这种机制有时在语法上有点笨拙:如果我有类似

(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 ...)]))