关于封装和封闭,我真的不明白.我相信封装是不可更改的,除非它被代码更改.但是当我被要求解释如何在代码上应用闭包和封装时,我无法理解.
例如 :
(define new-cercle #f) (let ((n 0)) (set! new-cercle (lambda (rayon) (begin (set! n (+ n 1)) (lambda (msg) (cond ((eq? msg ’circonference) (* 2 3.14 rayon)) ((eq? msg ’surface) (* 3.14 rayon rayon)) ((eq? msg ’nb-cercles) n)))))))
该n
封装,对不对?所以问题是:解释如何在此代码上应用封装和闭包.
我不明白的另一件事是为什么let
必须高于lambda?为什么当我把它放在下面时lambda
,功能不能很好并且没有累加器?
(define acc (let ((n 1)) (lambda (x) (set! n (* n x)) n)))
我希望有人会以一种简单的方式向我解释这一点,因为当我谷歌它时,说实话,我对大多数主题的复杂例子都不了解.
封装模式的名称,涉及将某些相关项放在一个容器中然后随该容器一起旅行的任何情况,并通过该容器上的某些访问机制进行引用.这些项可以是运行时值,也可以是编译时标识符等等.由多个字段组成的对象封装了字段:cons
单元格封装car
和cdr
.类封装了插槽.在一些对象系统中,方法也是如此.编译单元封装了它们的全局定义,例如函数和变量.
在OOP中流行使用"封装"是指将类定义为包含数据定义的单元,以及对其进行操作的方法:代码和数据是一个"封装".(Common Lisp对象系统不是这样的:方法没有封装在类中.)
闭包是别的东西,一些非常具体的:它是程序代码的身体,用其词法环境,一起具体化到功能类型的对象.在调用时,闭包的主体可以看到两组名称:闭包的函数参数,以及创建闭包的词法范围中的周围名称.闭包是封装的一个例子:它将代码体与词法范围封装在一起.访问胶囊的唯一方法是通过函数:函数就像一个"方法",捕获的词法环境的元素就像一个对象中的"槽".
(通过组合代码和数据,Lisp闭包类似于流行的封装概念,而不是Lisp类对象.)
关于那个有趣的词:在计算机科学中,"重新定义"程序的某些方面是采取不是第一类对象的东西,并以某种方式将其变成一个.
几乎任何适用于理解程序的可识别概念都可能具体化.(聪明的人必须提出一个关于如何做出明智的建议.)
例如,在执行中的给定点处的整个未来计算可以具体化,并将得到的对象称为延续(和未分隔延续,更精确地).
当连续运算符捕获未来的计算时,该未来变为假设:它实际上不会发生(不执行).相反,将执行另一种未来,其中将延续返回给操作员的调用者,或者将其传递给调用者指定的函数.现在具有此持续性的代码可以使用它来显式调用原始的捕获的未来,就像它是一个函数一样.或者选择不这样做.换句话说,程序控制流程(执行此程序段或不执行此程序,或多次执行)已成为一个功能对象(调用此函数或不调用它,或多次调用它).
对象是具体化的另一个例子:模块的具体化.老式程序分为具有全局函数和全局变量的模块.这种"模块"结构是我们可以在程序中识别并且有用地应用于描述这样的程序的概念.它很容易被物化:我们可以想象,如果我们有一个运行时对象是"模块",具有所有相同的属性,即包含函数和数据,该怎么办?并且,presto:基于对象的编程诞生了,具有同一模块的多个实例化等优点,可能因为变量不再是全局的.
cercle
和rayon
:首先,它的new-cercle
行为类似于对象的构造函数:它是一个可以从任何地方调用的全局函数.它维护了已构造对象的数量.只有该函数才能访问计数器,因此它是封装的.(实际上不仅该函数可以访问它,而且还有代表圆实例的闭包!)这是类模块封装的一个例子.它模拟模块,如Modula-2语言和类似模块,例如C语言翻译单元,static
在文件范围内有变量.
当我们调用时,new-cercle
我们必须为参数提供rayon
参数.生成并返回一个对象.该对象恰好是作为词法闭包产生的函数.这个闭包捕获了rayon
参数,从而封装了这个值:对象知道它自己的半径.我们可以new-cercle
反复调用,并获得不同的圆圈实例,每个实例都有自己的圆圈rayon
.这rayon
不是外部可见的; 它被封装在闭包内,并且只对该函数可见.
我们通过容器上的"消息"API间接访问人造丝容器.我们可以使用消息符号调用该函数surface
,并通过返回表面区域来回复.当前可用的消息都没有rayon
直接显示,但我们可以为其提供访问者消息,甚至可以提供更改半径的消息.甚至还有一条消息来访问共享变量n
,圆圈的数量,其行为类似于对象系统中的类变量(静态槽):任何圆形实例都可以报告已构造了多少个圆.(请注意,此计数不会通知我们当前存在多少个圆圈:当圆圈变为垃圾并被回收时,它不会减少:没有最终确定).
在任何情况下,我们都有一个容器,除了通过接口外,其内容无法访问.该容器将代码和数据绑定在一起,因此它不仅是封装,而且可以说是流行的OOP意义上的封装.