如何在Racket中将 `and` 作为函数传递?

6
以下是相关代码:

对于以下代码:

(foldl and #t '(#t #f))

Racket 返回:
and: bad syntax in: and

我知道 and 不是一个函数。我可以使用 lambda 来规避这个问题:

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

我这里有两个问题:

  1. and 不是一个函数。那它是什么?是一个宏吗?

  2. 我使用 lambda 的解决方案看起来很丑陋。有没有更好的方法来解决这个问题?

谢谢。


1
@jozefg 您是指 (foldl (cut and <> <>)#t'(#t #f)) 吗? 但是,SRFI-26 也说 (cut if <> 0 1) 是非法的,因为 if 不是“在R5RS意义上的表达式”,这似乎也使得 and 在那里不合法。 - Will Ness
@WillNess 我用 Racket 5.3 测试没问题。不确定这是否与具体实现有关。 - daniel gratzer
2
你可能会对我在另一个类似的问题(可能是重复的问题)中所提供的一个答案感兴趣,它探讨了一些可能的获取类似“and”的函数的方法,包括非短路(像你在问题中提供的那个)和短路。 - Joshua Taylor
@Sylwester 这就是我说“我不确定这是否是特定于实现的”原因 :) - daniel gratzer
1
@Sylwester 我知道什么是未定义行为,我承认这可能是UB,这只是一种观察。你完全正确,我只是不知道它是UB,并基于此做出了观察。 - daniel gratzer
显示剩余6条评论
1个回答

8

这是一个条件 句法形式,或者它可以被实现为一个宏,该宏会扩展为一些核心语法形式,编译器/解释器会将其视为特殊情况。

在Racket文档中的列表if列为一种特殊形式,但不包括and,因此后者很可能是基于前者实现的。但是R5RS将and列为句法关键字。因此,我们最好说它要么是一种特殊句法,要么是一个宏。

很容易将任何形如(and a b c ...)的表达式改写成if形式,即(if a (if b (if c #t #f) #f) #f)

lambda对我来说可以,但也可以使用SRFI-1中的every(或Racket中的andmap):

(every identity '(#t #f))

应该返回#f

编辑:除了Joshua Taylor指出的那样,通过像foldl这样的函数调用您的lambda不会短路。这就使得一开始调用and的目的失去了意义。

另一件事是,在Racket的foldl中,lambda的最后一个参数是在应用链中接收前一个结果的参数;因此实现实际上应该是

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接