macros - 为 xor 定义方案宏

标签 macros scheme lisp mit-scheme

请注意以下宏正在运行。

(define-syntax xor
  (syntax-rules ()
    ((xor a1 a2)
     (if a1
       (false? a2)
       (true? a2)))
    ((xor a1 a2 a3 ...)
     (let ((a (xor a1 a2)))
       (xor a a3 ...)))))

但是,如果我省略 a3 ,似乎一般情况下的参数列表中是无法正常工作的。

(define-syntax xor
  (syntax-rules ()
    ((xor a1 a2)
     (if a1
       (false? a2)
       (true? a2)))
    ((xor a1 a2 ...)
     (let ((a (xor a1 a2)))
       (xor a ...)))))

因此我想知道第二种情况下的省略号究竟发生了什么。

Q1.这是否意味着除了省略号之外的每个参数列表都应该是唯一的才能正常运行?

例如给定输入(xor #t #t #t) ,第一个将产生 #t ,而第二个将产生 #f .

我使用的解释器是mit-scheme .

Q2.是否可以使其短路?

谢谢

最佳答案

省略号告诉您有关第二个符号的信息。 a2 ... 可以是零个或多个元素,您需要在重复的内容中使用 a2 才能使其正常工作。在第二个宏中,a2 的结果缺少重复元素的省略号,并且 a 之后有 省略号,它不属于匹配模式并且也没有省略号。这两个事实都使宏无效。

第一个宏是正确的,因为您有一个术语匹配两个元素。您的第二个术语也匹配两个术语,但由于第一个匹配的模式已运行,您确定您的第二个模式有两个以上的参数,因为它匹配两个,且 a3 ... 至少为一个元素。

我不确定 true? 的用途。稍微简化一下:

(define-syntax xor
  (syntax-rules ()
    ((xor a1 a2)
     (if a1 (not a2) a2))
    ((xor a1 a2 a3 ...)
     (xor (xor a1 a2) a3 ...))))

(xor 1 2 3 4 5)  ; ==> 5  (odd number of true values)
(xor 1 2 3 4)    ; ==> #f (even number of true values)
(xor 1 2 3 4 #f) ; ==> #f (even number of true values)
(xor 1 #f #f #f) ; ==> #t (odd number of true values)

现在这将计算参数表达式的奇奇偶校验。由于它是触发器,所以不能短路。 (xor #t #t #f#f#t); ==> #t 因为它有奇数个真参数。这就是它的作用,虽然它是菊花链异或逻辑,但它实际上并没有剩下唯一一个真正的逻辑。由于您永远无法将其短路,因此您不妨使用执行完全相同操作的过程:

(define (xor . args)
  (= (remainder (count values args) 2) 1))

(xor 1 2 3 4 5)  ; ==> #t (odd number of true values)
(xor 1 2 3 4)    ; ==> #f (even number of true values)
(xor 1 2 3 4 #f) ; ==> #f (even number of true values)
(xor 1 #f #f #f) ; ==> #t (odd number of true values)

计数可以在 SRFI-1 list library 中找到.

xor还有另一种解释,这是我在阅读这个问题时想到的第一个解释,因为这是短路起作用的唯一情况。当一个表达式为真时,该表达式为真,否则结果为假。在这里,当遇到第二个假值时,您可以短路到 #f 而不评估其余参数。

(define-syntax xor
  (syntax-rules ()
    ((_) #f)
    ((_ a) a)
    ((_ a b ...)
     (if a
         (not (or b ...))
         (xor b ...)))))

(xor 1 2 3 4 5)  ; ==> #f (more than one true value)
(xor 1 2 3 4)    ; ==> #f (more than one true value)
(xor 1 2 3 4 #f) ; ==> #f (more than one true value)
(xor 1 #f #f #f) ; ==> #t (only one true value)

;; Slightly more complex version where 
;; the result is always the one true value or #f
(define-syntax xor
  (syntax-rules ()
    ((_) #f)
    ((_ a) a)
    ((_ a b ...)
     (let ((tmp a))
       (if tmp 
           (and (not (or b ...)) tmp)
           (xor b ...))))))

(xor 1 2 3 4 5)  ; ==> #f
(xor 1 2 3 4)    ; ==> #f
(xor 1 2 3 4 #f) ; ==> #f
(xor 1 #f #f #f) ; ==> 1 (the actual true value, consistent)

大多数算法不会因使用过程而产生任何速度损失,但我猜想在某些情况下该宏可能会作为宏派上用场。不保留值的过程版本与另一版本的过程版本非常相似:

(define (xor . args)
  (= (count values args) 1))

关于macros - 为 xor 定义方案宏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38944947/

相关文章:

macros - 从 &body 中获取 DECLARE 的更简洁的方法

list - 方案中的两个列表有什么区别

c++ - 类关键字后的宏变量

.rc 文件中的宏

json - ST-JSON JSO 对象的解构宏

lambda - Simply Scheme 第 09 章。Lambda。还有更多的 Lambda 练习吗?

syntax - 制作 "derived"标识符的最简洁方法?

lisp - flet 相当于 let*?

recursion - Lisp 无限递归

使用 ## 和 __LINE__ 创建 C 宏(与定位宏的标记串联)