【问题标题】:How to check if a list contains only #t如何检查列表是否仅包含#t
【发布时间】:2011-08-17 02:31:26
【问题描述】:

我在球拍和 MIT 方案中尝试使用以下代码,令我惊讶的是编译器抛出错误

(foldr and #t '(#t #t #f))

有什么方法可以使用 reduce/fold 方法来检查列表是否只包含真假? 我知道 lambda 可以完成这项工作,但它确实让我们想知道为什么这不是一个有效的代码。 我记得我可以在 Haskell 中做到这一点......

TIA。

【问题讨论】:

标签: scheme racket


【解决方案1】:

and 是一个宏,所以它本身没有值。具体来说,它会使评估短路,并且按照您的尝试使用它没有任何意义。出于这个原因,Racket 有andmap,您可以在这种情况下使用它。 (其他实现在不同的名称下具有类似的功能——例如,srfi-1 使用every。)

【讨论】:

  • 短路评估并不一定意味着无法折叠。 OP 不要求副作用。如果我and 初始化值和第一个元素,我应该得到一个真或假。 anding 第二个元素应该做同样的事情,等等。
  • 不,这并不意味着不能折叠 if 您愿意接受 (and ...) 在表单中和独立的 and 具有不同的语义。压倒性流行的选择是避免这种混乱。考虑一个事实,在任何具有标识符宏(包括 Racket)的 Scheme 实现中,实现这样一个双面 and 非常容易,而且这个问题远非从未讨论过的问题。
  • 那么还有另一种出路:(尝试)让两个and 表单共享相同的语义——另一个经过充分考虑的想法......一方面你会得到一些惊喜(@987654331 @ 变成了一种特殊的形式,或者你恢复到非短路行为),更重要的是,你得到了... fexprs,以及这意味着的所有乐趣。
  • 感谢您的回复!它真的很困扰我,我想不通,但我不得不说and 是一个宏,这让我很着迷。在测试时,我真的只有程序/功能......仍然是新的方案
【解决方案2】:

这在诡计中有效:

(primitive-eval (cons 'and '(#t #f)))

【讨论】:

  • 这适用于许多实现(在 Racket 中你会使用 eval),但由于其他原因,这是一个坏主意。 (例如,您要么吞下(let ((x 1)) (eval (cons 'and '(x)))) 不起作用的惊喜,要么避免使用类似andmap/every 的功能。)
  • 当然,如果我将列表构建为字符串,然后评估它会起作用的字符串。我认为 lisp 的全部意义在于程序和数据是同一个东西。
  • 不,从字符串评估代码具有完全相同的问题。我所说的避免它们的意思是避免对绑定的任何引用——这使您能够以与andmap 相同的方式减少值列表。
【解决方案3】:

and 是宏,不能用作函数。把它放在一个函数中:

(foldr (lambda (a b) (and a b)) #t '(#t #t #f))

【讨论】:

    【解决方案4】:

    有一点可能会出错,那就是在 Racket 和 Scheme 中,真正的值是 #f 以外的任何值。由于您的问题要求使用布尔值,因此以下内容将更具区分性:

    #lang racket
    (define (boolean-true? x) (eq? x #t))
    (define (only-contains-#t? l)
      (andmap boolean-true? l))
    

    例如,

    > (only-contains-#t? '())
    #t
    > (only-contains-#t? '(#t #t #t))
    #t
    > (only-contains-#t? '(#t #t true))
    #f
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-06-21
      • 2020-07-21
      • 1970-01-01
      • 1970-01-01
      • 2012-08-26
      • 2016-03-05
      • 1970-01-01
      相关资源
      最近更新 更多