如果我们要使用门,我们可能应该从定义构造它们的方法开始。我的意思是我们将不得不建造三个大门。
#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。