эллипсов говорит кое-что о втором символе. a2 ...
может быть ноль или более элементов, и вам нужно использовать a2
в том, что повторяется для его работы. В вашем втором макросе результат с a2
отсутствует эллипсис для повторяющихся элементов, и у вас есть ellipsis
после 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
, поскольку он содержит нечетное число истинных аргументов. Это о том, что он делает, и хотя логика логики xor
не содержит единственной истинной логики. Так как вы никогда не можете короткое замыкание это вы можете также использовать процедуру, которая делает ту же самую вещь:
(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)
Count можно найти в 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))
Возможный дубликат [функционального варианта «oneof» функции в Ракетка] (http://stackoverflow.com/questions/38820738/functional-variant-of-oneof-function-in-racket) –
Имеет ли смысл делать это как макрос вообще? 2-арное расширение должно оценивать второй аргумент независимо от первого, так как он отличается от функции '(lambda (a b) (если a (not b) b))'? –
@JoshuaTaylor Вы правы. Лучше определить его как функцию, если нет короткого замыкания. Здесь я просто хочу попробовать его как макрос и попытаться решить проблему с многоточием, см. ** Q1 **. И, согласно Сильвестру, похоже, существует способ сделать его короткое замыкание. Тогда макрос будет более полезен, чем функция в этом случае. – Ling