Exercise 4.14
1. The map of Eva can work, because Eva defines map in the calculator.
2. Why can't Louis map work?
First, let's take a look at the basic usage of map (in scheme, rather than in the valuer ):
(map (lambda (x) (* 2 x)) '(1 2 3 4))=> (2 4 6 8)
We can see that the difference between map function usage and other functions installed as basic procedures (such as cons and CDRS) is that it accepts a function as a parameter. Okay, let's assume that we implement map in louis's way. Now let's take a look at what happens when our calculator accepts the above calculator:
1) According to the calculator rule, we first evaluate the map operator and the parameter value:
;;; M-Eval input:map;;; M-Eval value:(primitive #<procedure:mmap>);;; M-Eval input:(lambda (x) (* 2 x));;; M-Eval value:(compound-procedure (x) ((* 2 x)) <procedure-env>);;; M-Eval input:'(1 2 3 4);;; M-Eval value:(1 2 3 4)
For comparison, let's look at their values in scheme:
> map#<procedure:mmap>> (lambda (x) (* 2 x))#<procedure>> '(1 2 3 4)(1 2 3 4)
2) when calling the evaluation process, the calculator will see (primitive # <procedure: mmap>), and it will take out the map version of the system, that is, # <procedure: mmap>, then apply it to the parameter (compound-procedure ...) at this time, the map will report an error:
procedure application: expected procedure, given: (procedure (x) ((* 2 x)) ……
As you can see, the system function map looks forward to the # <procedure> type process, and we give a list like procedure (x) (* 2 x. This list is generated by functions in our valuer:
(define (make-procedure parameters body env) (list 'procedure parameters body env))
Because the system version map does not know how to deal with the process generated by our valuer, the system version map cannot work normally.
3. How to Implement map correctly?
Perhaps the best way to understand this is to implement a map like Eva:
;; Exercise 4.14(define (eval-map exp env) (let ((proc (cadr exp)) (alist (cddr exp))) (apply-in-underlying-scheme map (lambda (x) (apply (eval proc env) (list x))) (list-of-values alist env))))(put 'map eval-map)
Test results:
;;; M-Eval input:(map (lambda (x) (* x 2)) '(1 2 3));;; M-Eval value:(2 4 6)
Note: The map implemented here is only the most basic map function. It can only accept one list, because our calculator processes any number of parameters, map cannot work in the following way:
(map + '(1 2 3) '(4 5 6))