SICP数据导向编程二维表操作与复数包实现问题解答
1. 构造函数的表项写入逻辑
put是二维操作表的写入过程,接收三个参数:第一参数是操作名(第一维键),第二参数是类型标签(第二维键),第三参数是键对绑定的值。
你看到的代码:
(put 'make-from-real-imag 'rectangular (lambda (x y) (tag (make-from-real-imag x y))))
是直角坐标包安装时直接执行的语句——你运行(install-rectangular-package)的过程中,这行代码就会调用insert!完成表项写入,不需要等手动调用构造函数才写表。
这里存入的是一个闭包,捕获了直角坐标包内部的打标函数tag、以及包内私有的直角坐标构造函数make-from-real-imag。后续全局调用通用make-from-real-imag时,就会从表里取出这个lambda,传入x、y参数,返回带rectangular标签的直角坐标复数对象。
2. get查询返回过程而非false的原因
这个返回结果完全正常,不是代码错误——对应表项本来就存在。你运行install-rectangular-package时已经执行了(put 'real-part '(rectangular) real-part),把包内部定义的(lambda (z) (car z))(也就是你代码里写的(define (real-part z)(car z)))绑定到了对应键位,查得到才是正确行为。只有没跑安装包、或者键名/标签写错时,get才会返回false。
顺带提一句,你贴的直角坐标包代码有个笔误:内部定义的(define (make-from-real-imag)(cons x y))漏了x、y形参,后续调用构造函数会报错,改成(define (make-from-real-imag x y)(cons x y))即可。
3. 直接传入选择子过程的逻辑
这是Scheme的一等过程特性:过程和数值、字符串一样,本身就是可以传参、存入数据结构的一等值,传入的时候不需要带参数。(put 'real-part '(polar) real-part)里第三个参数传的是极坐标包内部real-part过程本身的引用,不是调用后的返回值。要是这里加了参数写成(real-part z),安装包阶段就会直接报错——根本没有定义z这个变量,没法执行过程。
这么写的作用是提前把各类型对应的操作实现存在表里,等通用分派逻辑运行时,按数据的类型标签查到对应过程,再传实际参数调用。比如给极坐标复数求实部时,系统先拿到数据的polar标签,查表找到real-part对应polar类型的实现过程,再把复数内容传进去计算结果即可。
内容的提问来源于stack exchange,提问作者PyotrVanNostrand

