rns*_*nso 2 scheme functional-programming xor racket
我编写了以下函数来查找5个变量中只有一个是否为真:
(define (oneof v w x y z)
(or (and v (not w) (not x) (not y) (not z))
(and w (not v) (not x) (not y) (not z))
(and x (not v) (not w) (not y) (not z))
(and y (not v) (not w) (not x) (not z))
(and z (not v) (not w) (not x) (not y)) ))
Run Code Online (Sandbox Code Playgroud)
(xor只有2个参数)
但是,这是非常必要的,而不是功能性的.此外,我想写一个函数(oneof N),它将是通用的而不是5个变量的特定.如何才能做到这一点?谢谢.
编辑:正如评论中所指出的,代码是"重复的"而不是"命令性的",尽管仍需要改进.
你的最后一个音符是准确的:它听起来像是xor正确的功能但是这个,但它只需要两个参数.如果xor采取任何数量的论点可能会更好,但鉴于它没有,我们可以自己实施.
也许最天真的方式就是计算真值的数量并检查这个数字是否正好1.我们可以用count或者for/sum,根据你的偏好来做:
; using count
(define (xor . args)
(= 1 (count identity args)))
; using for/sum
(define (xor . args)
(= 1 (for/sum ([x (in-list args)])
(if x 1 0))))
Run Code Online (Sandbox Code Playgroud)
这两个都有效,但它们不保留Racket的有用属性xor,它在成功时返回单个truthy元素,而不是总是返回一个布尔值.要做到这一点,我们可以使用折叠,使用foldl,foldr或for/fold.但是,鉴于我们希望尽快退出,使用#:final选项for/fold非常方便:
(define (xor . args)
(for/fold ([found #f])
([arg (in-list args)])
#:final (and found arg)
(if (and found arg) #f
(or found arg))))
Run Code Online (Sandbox Code Playgroud)
然而,这实际上仍然不是最佳的.的两个参数的版本xor是一个函数,而不是像宏and和or,因为它不能在任其参数懒惰.然而,xor实际上可以有很多论点.为了添加这种短路行为,我们可以写成xor一个宏:
(define-syntax xor
(syntax-rules ()
[(_) #f]
[(_ x) x]
[(_ x rest ...)
(let ([v x])
(if v
(and (nor rest ...) v)
(xor rest ...)))]))
Run Code Online (Sandbox Code Playgroud)
一般来说,这就像以下的功能版本一样xor:
> (xor #f #f #f #f #f)
#f
> (xor #f #f 1 #f #f)
1
> (xor #f #f 1 2 #f)
#f
Run Code Online (Sandbox Code Playgroud)
然而,喜欢and和or它有时会"短路",如果结果不会影响,则不评估表达式:
> (xor #f #f #f #f (begin (displayln "hello!") #f))
hello!
#f
> (xor #f #f 1 #f (begin (displayln "hello!") #f))
hello!
1
> (xor #f #f 1 2 (begin (displayln "hello!") #f))
#f
Run Code Online (Sandbox Code Playgroud)
(请注意,hello!在最后一个示例中永远不会打印出来.)
这是一个好主意,这是一个坏主意......?我真的不知道.这种行为似乎不太可能非常有用,并且增加了很多复杂性.它还可以防止xor被高阶使用,但是syntax-id-rules当xor在表达式位置使用时,你可以使用并扩展到过程版本.尽管如此,它可能很有趣,并且它使其行为更加符合and和or,所以我认为我将它包括在内以保证完整性.