Macros Scheme宏-将列表展开为一组函数调用

Macros Scheme宏-将列表展开为一组函数调用,macros,scheme,Macros,Scheme,此识别tic tac toe行标记的程序不起作用(X行未标记时被识别为完全标记) (定义(韩元?百万) (定义(标有?r的行) (每?-ec(:向量c(索引i)b)(if(memv i r))[char=?cm])) “如果m赢了,则返回#t” (让([rr'((0112)(345)(678)(036)(147)(258)(048)(246))) `(或,@(映射(lambda(r)`(行标记)(列表,@r)))rr))) 而下面的程序是有效的 (定义(韩元?百万) (定义(标有?r的行) (

此识别tic tac toe行标记的程序不起作用(X行未标记时被识别为完全标记)

(定义(韩元?百万)
(定义(标有?r的行)
(每?-ec(:向量c(索引i)b)(if(memv i r))[char=?cm]))
“如果m赢了,则返回#t”
(让([rr'((0112)(345)(678)(036)(147)(258)(048)(246)))
`(或,@(映射(lambda(r)`(行标记)(列表,@r)))rr)))
而下面的程序是有效的

(定义(韩元?百万)
(定义(标有?r的行)
(每?-ec(:向量c(索引i)b)(if(memv i r))[char=?cm]))
“如果m赢了,则返回#t”
(或(标有“0 1 2”的行)(标有“3 4 5”的行)(标有“6 7 8”)的行)
(标有“0 3 6”的行)(标有“1 4 7”的行)(标有“2 5 8”的行)
(标有“0 4 8”的行)(标有“2 4 6”的行)
我试过了,但运气不好

(let([rr'((0112)(345)(678)(036)(147)(258)(048)(246)))
`(或,@(映射(lambda(r)`(标有?的行,r))rr)))

(let([rr'((0112)(345)(678)(036)(147)(258)(048)(246)))
`(或,@(map(lambda(r)`(标有?’的行,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"
  (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
是否可以是扩展名为
(或(行标记…)
)的宏?不可以,因为宏转换源代码,并且绑定到
rr
的列表在运行时之前不可用:宏没有需要转换的源代码

实际上,这里要避免的是,
行标记?
主体中的表单在返回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 ...)]))

您使用的是什么方案?我使用的是Gauche这不是一个宏,它是一个生成列表
(或(行标记为…
)的过程。有没有一种方法可以使列表在不使用
eval
的情况下可执行?我的目标是避免代码重复并自动生成可执行文件
(或…)
表达式,同时保持
每个ec的短路
是的,您可以用宏来实现。感谢您的回答!回答解决了问题,所以我接受它,但回答没有解释如何使问题中的代码工作。我理解问题中的过程返回是一个列表
”(或(行标记?…
,但如何使此列表可以通过宏执行仍然是一个问题。我添加了一个附录,解释了为什么在这里不能使用任何有用的宏。非常感谢您的解释,并强调了一个事实,即可以通过宏转换的源代码与runti之间存在巨大差异从源代码中提取的变量值必须用过程而不是宏进行转换!这真的很有用,很有帮助!谢谢你!