布尔值与谓词
介绍布尔值 #t 与 #f、常用谓词、逻辑运算符 and/or/not 等,以及「非假即真」的真值规则。
布尔值:真与假
布尔值(boolean)的严格定义是:只有”真”和”假”两种可能取值的二元变量。布尔值在表达条件表达式(conditional)时极其有用——条件表达式就是根据测试结果选择行动的指令。一个符合逻辑的例子是:如果我们没有牛奶了,就去商店;否则,把牛奶加进麦片里,享用吧。
为了测试我们是否没有牛奶了,我们需要用到布尔值。Racket 中的”真”用 #t 或 true 表示,“假”用 #f 或 false 表示。
-> (= 1 1)
#t
-> (= 1 2)
#f
> (if #t
'(the condition was true)
'(the condition was false))
(the condition was true)
> (if #f
'(the condition was true)
'(the condition was false))
(the condition was false)
> (if (= 1 1)
'(the condition was true)
'(the condition was false))
(the condition was true)
谓词
调用时返回 true 或 false 的函数称为谓词(predicate)。例如,even? 就是一个用来测试数是否为偶数的谓词。
-> (even? 2)
#t
-> (even? 3)
#f
谓词永远不会返回 #t 或 #f 以外的值。下面列出了一些 Racket 中实用的预定义谓词。这个列表并不全面,在以后的课程中你肯定还会发现更多谓词。
数学运算符
Racket 提供了比较数值所需的标准数学运算符:
<当第一个实参小于第二个时返回#t。>当第一个实参大于第二个时返回#t。=当两个实参相等时返回#t。<=当第一个实参小于或等于第二个时返回#t。>=当第一个实参大于或等于第二个时返回#t。
警告
这些谓词只对数有效。用它们比较词、句子或任何其他类型的值都会产生错误。
-> (= (+ 3 3) 6)
#t
-> (= 'foo 'foo)
; =: contract violation
; expected: number?
; given: 'foo
; argument position: 1st
; [,bt for context]
member?
member? 接收一个字母和一个词时,若词中包含该字母则返回 #t,否则返回 #f。member? 接收一个词和一个句子时,若句子中包含该词则返回 #t,否则返回 #f。
-> (member? 'a 'aeiou)
#t
-> (member? 'b 'aeiou)
#f
-> (member? 'foo '(foo bar baz))
#t
-> (member? 'foobar '(foo bar baz))
#f
empty?
谓词 empty? 接收一个任意类型的实参,若实参是空词 "" 或空句子 '() 则返回 #t,否则返回 #f。
-> (empty? "")
#t
-> (empty? 'foo)
#f
-> (empty? '())
#t
-> (empty? '(foo bar baz))
#f
-> (empty? 3)
#f
equal?
equal? 接收两个任意类型的实参,若它们相同则返回 #t,否则返回 #f。
-> (equal? (+ 1 1) 2)
#t
-> (equal? 3 1)
#f
-> (equal? 'foo 'foo)
#t
-> (equal? '(foo bar baz) '(foo bar baz))
#t
-> (equal? + +)
#t
类型检查器
Racket 还提供了一类谓词,用于检查值是否属于某种特定类型:
number?检查值是否为数。word?检查值是否为词。sentence?检查值是否为句子。boolean?检查值是否为布尔值。
用作谓词的复合过程
你完全可以创建自己的谓词,因为它们本质上就是过程。例如:
(define (vowel? letter)
(member? letter 'aeiou))
vowel? 检查实参字母是否为元音。
检验理解
注意: 这是作业中的练习 2。
写一个名为 teen? 的谓词,接收一个数作为实参,若该数在 13 到 19 之间(含两端)则返回 #t。
非假即真
判断一个表达式为真还是为假时,务必记住:除非为假,任何值都算真。这意味着所有的数、词、句子和过程都是真的,包括 ""、'() 和 0。下面是一些违反直觉的例子,不妨思考一下:
-> (false? "") ;; "" 是假吗?
#f ;; 不,不是
-> (false? '())
#f
-> (false? 0)
#f
-> (false? false?) ;; 过程 false? 是假吗?
#f ;; 不,这个过程本身不是假
逻辑运算符
我们还可以在 Racket 中使用逻辑运算。
and
and 是一个可接收任意数量、任意类型实参的谓词。如果所有实参都不为假,它返回最后一个实参;否则返回 #f。例如:
-> (and 1 2 3)
3
-> (and (= 1 1) (member? 'a 'aeiou))
#t
-> (and (number? 'hi) 2 3)
#f
or
or 是一个可接收任意数量、任意类型实参的谓词。它返回第一个不为假的实参;如果所有实参都不为真,则返回 #f。例如:
-> (or (even? 4) (= 1 1))
#t
-> (or 1 #f 2)
1
-> (or (even? 1) #f (number? 'foo))
#f
not
not 接收一个任意类型的实参,简单地对它取反。例如:
-> (not #f)
#t
-> (not #t)
#f
-> (not 3)
#f
-> (not (and (and 3 3) (or #f #f)))
#t
nand
nand 等价于 (not (and ...。例如:
-> (nand #f #t)
...(not (and #f #t))
...(not #f)
#t
nor
nor 想必你已经猜到了,等价于 (not (or ...。例如:
-> (nor #f #t)
...(not (or #f #t))
...(not #t)
#f
xor
xor 接收两个任意类型的实参,若恰好只有一个(不多不少)实参不是 #f,则返回该实参;否则返回 #f。
-> (xor 11 #f)
11
-> (xor #f 11)
11
-> (xor 11 22)
#f
-> (xor #f #f)
#f