是否将此Scheme函数转换为其他形式?
这里有一种方法可以将sum定义为消息传递对象:是否将此Scheme函数转换为其他形式?,scheme,message-passing,Scheme,Message Passing,这里有一种方法可以将sum定义为消息传递对象: (define (make-sum . exps) (let ((len (length exps))) ;; first handle variable length operands (cond ((= len 0) (make-number 0)) ;; base case for addition ((= len 1) (car exps)) ;; might as well dr
(define (make-sum . exps)
(let ((len (length exps)))
;; first handle variable length operands
(cond
((= len 0) (make-number 0)) ;; base case for addition
((= len 1) (car exps)) ;; might as well drop the sum if only 1 argument
((> len 2)
(make-sum (car exps) (apply make-sum (cdr exps))))
;; apply is described in section 2.4, footnote 47
;; > 2 operands: break up into 2 for simplicity in handling
(else ;; must be exactly 2 operands
(let ((op1 (car exps))
(op2 (cadr exps)))
(cond ((op1 'zero?) op2) ;; exp + 0 --> exp
((op2 'zero?) op1)
((and (op1 'number?) (op2 'number?))
(make-number (+ (op1 'value) (op2 'value)))) ;; num + num --> num
(else ;; create a new message-passing object representing the sum
(lambda (m . args)
(cond ((eq? m 'derive)
(if (and (= (length args) 1)
(symbol? (car args)))
;; derivative of a sum is the sum of the derivatives
;; of the parts of the sum
(make-sum (op1 'derive (car args))
(op2 'derive (car args)))
(error "derive needs a variable argument")))
((eq? m 'print) (list '+ (op1 'print) (op2 'print)))
((eq? m 'zero?) #f)
((eq? m 'number?) #f)
((eq? m 'value)
(error "should not be asking for the value of a sum expression"))
((eq? m 'evaluate)
(if (and (= (length args) 2)
(symbol? (car args))
(number? (cadr args)))
(let ((eop1 (op1 'evaluate (car args) (cadr args)))
(eop2 (op2 'evaluate (car args) (cadr args))))
(make-sum eop1 eop2))
(error "evaluate needs a variable symbol and a number")))
((eq? m 'has-constant-multiplier?) #f)
((eq? m 'merge-constant)
(error "should not be merging a constant with an addition"))
(else (error "unknown message" m)))))))))))
但这可以改写为:
(define (make-sum exp1 exp2)
(cond ((exp1 'zero?) exp2) ;; exp + 0 --> exp
((exp2 'zero?) exp1)
((and (exp1 'number?) (exp2 'number?))
(make-number (+ (exp1 'value) (exp2 'value)))) ;; num + num --> num
(else ;; create a new message-passing object representing the sum
(lambda (m . args)
(cond ((eq? m 'derive)
(if (and (= (length args) 1)
(symbol? (car args)))
(let ((variable (car args)))
;; derivative of a sum is the sum of the derivatives
;; of the parts of the sum
(make-sum (exp1 'derive variable)
(exp2 'derive variable)))
(error "derive needs a variable argument")))
((eq? m 'print) (list '+ (exp1 'print) (exp2 'print)))
((eq? m 'zero?) #f)
((eq? m 'number?) #f)
((eq? m 'value)
(error "should not be asking for the value of a sum expression"))
((eq? m 'evaluate)
(if (and (= (length args) 2)
(symbol? (car args))
(number? (cadr args)))
(let ((variable (car args))
(number (cadr args)))
(let ((exp1-eval (exp1 'evaluate variable number))
(exp2-eval (exp2 'evaluate variable number)))
(make-sum exp1-eval exp2-eval)))
(error "evaluate needs a variable symbol and a number")))
(else (error "unknown message: " m)))))))
如何将我编写的用于将产品定义为消息传递对象的函数更改为上述第二种格式?
以下是我编写的代码:
(define (make-product . exps)
(let ((len (length exps)))
(cond
((= len 0) (make-number 1)) ;; base case for multiplication
((= len 1) (car exps)) ;; might as well drop the product if only 1 argument
((> len 2) (make-product (car exps) (apply make-product (cdr exps))))
(else
(let ((op1 (car exps))
(op2 (cadr exps)))
(cond ((op1 'zero?) (make-number 0))
((op2 'zero?) (make-number 0))
((and (op1 'number?) (= (op1 'value) 1)) op2) ;; multiplicative identity
((and (op2 'number?) (= (op2 'value) 1)) op1) ;; multiplicative identity
((and (op1 'number?) (op2 'has-constant-multiplier?))
(op2 'merge-constant (op1 'value)))
((and (op2 'number?) (op1 'has-constant-multiplier?))
(op1 'merge-constant (op2 'value)))
(else
(lambda (m . args)
(cond ((eq? m 'derive)
(if (and (= (length args) 1)
(symbol? (car args)))
(make-sum
(make-product (op1 'derive (car args)) op2)
(make-product op1 (op2 'derive (car args))))
(error "derive needs a variable argument")))
((eq? m 'print) (list '* (op1 'print) (op2 'print)))
((eq? m 'zero?) #f)
((eq? m 'number?) #f)
((eq? m 'value)
(error "should not be asking for the value of an product expression"))
((eq? m 'evaluate)
(if (and (= (length args) 2)
(symbol? (car args))
(number? (cadr args)))
(let ((eop1 (op1 'evaluate (car args) (cadr args)))
(eop2 (op2 'evaluate (car args) (cadr args))))
(make-product eop1 eop2))
(error "evaluate needs a variable symbol and a number")))
((eq? m 'has-constant-multiplier?)
(or (op1 'has-constant-multiplier?)
(op2 'has-constant-multiplier?)))
((eq? m 'merge-constant)
(if (and (= (length args) 1)
(number? (car args)))
(cond ((op1 'has-constant-multiplier?)
(make-product
(op1 'merge-constant (car args))
op2))
((op2 'has-constant-multiplier?)
(make-product
op1
(op2 'merge-constant (car args))))
(else
(error "should not be calling merge-constant on a product with no constant multiplier")))
(error "invalid arguments to merge-constant")))
(else (error "unknown message" m)))))))))))
两个make sum函数的主要区别在于,第二个函数是二进制(2参数)函数,而第一个函数有变量。将第一个
cond
从第一个makesum
中删除,您基本上拥有了第二个makesum
。第二个不处理'has-constant-multiplier?
或'merge-constant
,但其他差异完全是装饰性的。从这一点上,您可以得出结论,从make product
中剥离vararg外壳是您需要做的。我只知道Common Lisp,所以我被(op1'编号?)
搞糊涂了——这不应该是(编号?op1)
?啊!我亲眼目睹了这一计划的实施所带来的恐怖。谁来帮帮我,我的眼睛在流血。我一直认为Scheme/Lisp看起来像蓬松的云。。。这似乎令人欣慰。@Harleqin,这是scheme中常见的OOP技术,“object”实际上是一个函数,它的第一个参数是标识符,大致相当于消息名,因此(op1'number?)相当于C#/Java中的类似“op1.isNumber()”的东西