2011-05-02 30 views
7

我用球拍和MIT方案下面的代码尝试,让我感到吃惊的是,编译器扔犯错如何检查列表中只包含#T

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

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

TIA。

+0

你得到什么错误讯息? – brandizzi 2011-05-02 16:37:51

+0

Scheme和Racket不完全相同,但是您可以在[在Scheme中使用AND与apply函数](http://stackoverflow.com/q/387775/1281433)中找到解决方案。 – 2015-01-16 14:45:08

回答

8

and是一个宏,所以它本身没有值。具体来说,它会对评估进行短路,并将其用于尝试无法理解的情况。出于这个原因,球拍有andmap,你可以在这种情况下使用。 (其它实施方式具有不同的名称类似的功能 - 例如,SRFI-1采用every。)

+0

短路评估不一定​​意味着无法折叠。 OP没有要求副作用。如果我'和'初始化值和第一个元素,我应该得到一个真或假。 '和'与第二个元素应该做同样的,等等。 – drysdam 2011-05-02 17:18:21

+0

不,这并不意味着无法折叠*如果*你愿意接受'(和...)'的形式和独立的'和'具有不同的语义。压倒性的流行选择是为了避免这种混淆。考虑一下这样一个事实,即在任何具有标识符宏(包含Racket)的Scheme实现中,实现这样的双重'和'是非常容易的,而且这个问题远没有讨论过。 – 2011-05-02 18:16:44

+0

然后还有另一个出路:(试着)让'和'形式共享相同的语义 - 另一个好的散列思想......一方面你会得到一些惊喜('foldl'成为一种特殊的形式,或者你回到非短路行为),而在更重要的方面,你会得到...... fexprs,以及所有这些暗示的乐趣。 – 2011-05-02 18:20:27

1

这适用于诡计:

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

仍然是新的,这在许多实现中都有效(在Racket中你会使用'eval'),但由于其他原因,这是一个坏主意。 (例如,要么让你吃惊('((x 1))(eval(cons'和'(x))))'不起作用,或者避免让''和map'/'''''''''''''' – 2011-05-02 18:26:00

+0

当然,如果我建立了列表*作为字符串*然后评估字符串,它将起作用。我认为lisp的重点在于程序和数据是相同的东西。 – drysdam 2011-05-02 18:34:37

+0

不,评估字符串中的代码具有完全相同的问题。我的意思是避免使用绑定 - 这会让你很容易以'和'map'的方式减少值列表。 – 2011-05-02 23:00:42

7

而且是宏,并且不能被用作一个函数。把它放在一个函数:

可能是关闭

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

1

一件事是,在球拍和方案,真值比#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