Problem 4: and
and or
In the programming language scheme, nearly every piece of syntax forms can be built by macro.
You may find that the behavior of scheme builtin and
and or
is a little weird.
In this problem, we will have a deeper understanding of them by building our version of and
and or
For and
, we know that:
(and) = #t
(and 1) = 1
(and x1 x2 x3 ... xn) = #f
if there is axi
eval to#f
, otherwise(and x1 x2 x3 ... xn)
eval toxn
.
In fact, (and x1 x2 x3 ... xn)
can be transformed to this equivalent form:
; (let ...) is not required here
; when implement (or ...), (let ...) wrap is required
(let ((t x1))
(if t
(let ((t x2))
(if t
(let ((t x3))
...
#f))
#f)))
E.g. (and 1 #t 's)
is equivalent to
(let ((t 1))
(if t
(let ((t #t))
(if t
's ; Note: here we don't need to wrap 's with (if ... )
; why ?
#f))
#f))
So, we can write this macro to transform and
expression:
Note:
- cs61a scheme doesn't support varargs macro, so we have to put all the operands into a list in our version of
and
andor
. ofand
(e.g.(and (1 #t 's))
)- cs61a scheme doesn't allow shadowing of builtin functions, so we have to use another name for our
and
(my/and
).
(define-macro (my/and operands)
(cond
((null? operands) #t)
((null? (cdr operands)) (car operands))
(else
`(let ((t ,(car operands)))
(if t
(my/and ,(cdr operands))
#f)))))
scm> (my/and ())
#t
scm> (my/and (1 2))
2
scm> (my/and (1 #f 3))
#f
Now, use the same technique to implement my/or
, (my/or (x1 x2 x3 ...))
should be equivalent to (or x1 x2 x3 ...)