到目前为止,我假设最后两个应该是:
(define or-gate
(lambda (a b)
(if (= a 1)
1
(if (= b 1)
1
0))))
(define xor-gate
(lambda (a b)
(if (= a b)
0
1)))
。但 AND 令人费解。我该如何实现它?
如果我们记住=
可以接受两个以上的参数,这很简单:
(define and-gate
(lambda (a b)
(if (= a b 1)
1
0)))
换句话说:and
逻辑连接器是true
当且仅当它的两个参数都true
,对于所有其他参数,它是false
。
and
的真值表是什么? 实际上,如果您有and
或or
或xor
中的任何一个真值表,那么算法是相同的。
让我们创建一个接受真值表并返回一个计算门逻辑的函数的函数
(define (gate-logic-for-truth-table table)
(lambda (a b)
(vector-ref (vector-ref table b) a)))
现在,使用and
的真值表,我们生成and-gate
函数:
(define and-gate (gate-logic-for-truth-table
'#(#(0 0)
#(0 1))))
还有一个小型测试:
> (and-gate 0 0)
0
> (and-gate 0 1)
0
> (and-gate 1 0)
0
> (and-gate 1 1)
1
假设参数1
或0
:
对于or
,您无需查看a
是否1
b
- 结果是 1
。否则,结果为 b
。
对于and
,您无需查看b
a
是否0
- 结果是0
。否则,结果b
.
如果你想让它尽可能类似于or-gate
,你可以在外部条件中用 0
s 替换 1
s:
(define and-gate
(lambda (a b)
(if (= a 0)
0
(if (= b 1)
1
0))))
或者,如果你想坚持与1
进行比较,你可以重新排列分支:
(define and-gate
(lambda (a b)
(if (= a 1)
(if (= b 1)
1
0)
0)))
可以缩短代码:
(define and-gate
(lambda (a b)
(if (= a 1)
b
0)))
和
(define or-gate
(lambda (a b)
(if (= a 1)
1
b)))
但这是否更具可读性是相当个人化的。
如果我们要使用门,我们可能应该从定义一个构造它们的方法开始。我的意思是,我们将不得不建造三个门。
#lang racket
;; Gate Constructor
(define (make-gate predicate)
(lambda (A B)
(predicate A B)))
然后,我们可以使用一厢情愿的想法在高层次上定义门:
(define and-gate
(make-gate and-predicate))
(define or-gate
(make-gate or-predicate))
(define xor-gate
(make-gate xor-predicate))
然后我们可以任意定义内部门逻辑,无论我们喜欢什么:
(define (and-predicate A B)
(let ([a (if A 1 0)]
[b (if B 1 0)])
(= 2 (+ a b))))
(define (or-predicate A B)
(let ([a (if A 1 0)]
[b (if B 1 0)])
(< 0 (+ a b))))
(define (xor-predicate A B)
(let ([a (if A 1 0)]
[b (if B 1 0)])
(= 1 (+ a b))))
然后我们做真正的测试工作...好吧,也许我们实际上应该从编写测试开始。
(module+ test
(require rackunit
rackunit/text-ui)
(define (make-test-harness test-function)
(define (test-harness ins outs)
(if (or (null? ins)
(null? outs))
'test-complete
(begin
(test-function (first ins)
(first outs))
(test-harness (rest ins)
(rest outs)))))
test-harness))
(define gate-inputs
'((#f #f)
(#t #f)
(#f #t)
(#t #t)))
(define and-truth-table
'(#f #f #f #t))
(define or-truth-table
'(#f #t #t #t))
(define xor-truth-table
'(#f #t #t #f))
(define (make-gate-test gate name)
(lambda (input correct)
(define A (first input))
(define B (second input))
(test-equal? name
(gate A B)
correct)))
(define and-gate-test
(make-gate-test and-gate "AND Gate Test"))
(define or-gate-test
(make-gate-test or-gate "OR Gate Test"))
(define xor-gate-test
(make-gate-test xor-gate "XOR Gate Test"))
(define (and-tests)
(define tests
(make-test-harness and-gate-test))
(tests gate-inputs and-truth-table))
(define (or-tests)
(define tests
(make-test-harness or-gate-test))
(tests gate-inputs or-truth-table))
(define (xor-tests)
(define tests
(make-test-harness xor-gate-test))
(tests gate-inputs xor-truth-table))
(define-test-suite
all-gate-tests
(and-tests)
(or-tests)
(xor-tests))
(run-tests all-gate-tests))
运行测试
racket@29761897.rkt> ,enter "/home/ben/StackOverflow/29761897.rkt"
12 success(es) 0 failure(s) 0 error(s) 12 test(s) run
0
由于所有测试都通过了,我们现在可以上交家庭作业[一如既往地受学术政策的约束]。
笔记
使用真值#f
和#t
为Racket的测试工具提供了更清晰的钩子。它还允许直接编写谓词,而不是序列化和反序列化1
和0
。
下面是一个简单的定义,其中真值表很清楚:
(define (and-gate a b)
(cond
[(and (= a 0) (= b 0)) 0]
[(and (= a 0) (= b 1)) 0]
[(and (= a 1) (= b 0)) 0]
[(and (= a 1) (= b 1)) 1]))
如果我们注意到只有一个子句的结果是 1,而所有其他子句都给出 0,我们可以写:
(define (and-gate a b)
(cond
[(and (= a 1) (= b 1)) 1]
[else 0]))