【问题标题】:In Scheme, can if be expressed as a combination of boolean operators?在 Scheme 中,if 可以表示为布尔运算符的组合吗?
【发布时间】:2011-02-04 15:53:21
【问题描述】:

if 表示andornot 很容易(借助or 的本地绑定)。我想知道反过来是不是真的。我天真的第一次尝试:

(if test conseq altern) => (or (and test conseq) altern)

但是,如果test 不是#fconseq#f,则转换结果为altern,这是不正确的。

在保持if 的短路特性的同时,是否有一个转换为正确的值?

【问题讨论】:

  • 也许(或(和测试(或结果#t))交替)?
  • 啊,但是 (if #t #f #t) 将评估为 #t。不过,这些是我正在寻找解决问题的技巧。

标签: scheme boolean-logic syntactic-sugar


【解决方案1】:

听起来你已经很好地解释了为什么 ifandor 做得更多。但如果你可以作弊并添加lambda 以延迟实际结果:

(define-syntax-rule (if c t e) ((or (and c (lambda () t)) (lambda () e))))

【讨论】:

  • 不错;我喜欢增加一点懒惰的想法。关于如何在不作弊的情况下实现这一点的任何想法?
  • 懒惰是没有必要的。重要的是把它包裹在任何使它评估为真的东西中,然后提取它
  • 需要那种懒惰——换句话说,你需要包装来包含一个计算而不是一个。否则你不会得到使(if #f (print-stuff) 1) 不打印东西的短路属性。
  • Barzlay:短路已经由andor 完成
  • @user102008 但是conseqaltern 表达式不会被评估,而Scheme 的内置f 可以避免吗?
【解决方案2】:

尝试(or (and test conseq) (and (not test) altern)) 作为一般模式。通过在第二个and 中否定test,它确保外部析取将是conseq#f 如果test 为真,或#faltern 如果test 为假。

【讨论】:

  • 缺点是这可以评估“测试”两次
  • 不错;本地绑定test 并使用此模式看起来可行。不过,我想知道是否可以不绑定?
【解决方案3】:

这与 Eli Barzilay 的回答相同,只是我没有将其包装在 lambda 中,而是将其包装在 1 元素列表中

(if test conseq altern) => (car (or (and test (list conseq)) (list altern)))

顺便说一下,2.5 之前的 Python 就有这个问题。在 Python 中编写条件表达式(即 C 中的 test ? conseq : altern,Scheme 中的 if 就是这样)没有很好的方法。最简单的尝试是

test and conseq or altern

这在大多数情况下都有效,但当conseq 在 Python 中被认为是错误的(即 False、0、空列表、空字符串等)时失败。这是您在上面发现的确切问题。解决方法是将其包装在一个列表中(非空列表始终为真)并再次提取它:

(test and [conseq] or [altern])[0]

看起来很丑。这就是他们在 Python 2.5 中添加语法 conseq if test else altern 的原因。

【讨论】:

    猜你喜欢
    • 2014-05-30
    • 2017-01-09
    • 1970-01-01
    • 1970-01-01
    • 2020-09-17
    • 1970-01-01
    • 2021-02-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多