1x Forth
Charles Moore, April 13, 1999
这篇文章是 Jeff Fox 根据 Charles Moore 谈话录音所写。
我请求 Chuck Moore 允许我对这次关于 15 年来 Forth 语言变迁的谈话进行录像。我们安装了摄像机,他谈论了我在这个网站上提出的问题,但是这一次我们不再把焦点集中在固体物理、 VLSI 或者芯片和调试方面的经验,而是 Forth 语言。我觉得他谈论了这些年来的 Forth 语言,但是相比我所关心的、 30 年前发明的语言来说,他谈及了更多的方面。
我介绍 Chuck.
(Jeff Fox) 今天,我请 Chuck Moore 对 Forth 做一个介绍,我想请他谈一谈对于自己发明的语言在最近 15 年里的经验。现在我们请 Charles Moore 。
(Charles Moore) 这可是一个大话题,我们谈多长时间?
(Jeff) 磁带只有一个小时。
(Chuck) 15 年,那差不多是我用计算机面对软件的整个经历。回想 15 年前,把重点从 Forth 语言转向 Forth 微处理器的动机主要有两个。
首先是软件的问题已经解决了。编写应用程序很容易,不用费太大的劲。所有的问题都是硬件,硬件笨拙、零乱、可靠性差,特别是你需要为客户的硬件而编写客户化的软件时。如果你想调试硬件那就更是一个大麻烦。这些都说明硬件工程师并没有做出出色的工作,当然,他们比工业界的软件工程师做得好,但是没有 Forth 软件工程师做得好。因此我想看看我能够在这些硬件问题方面做些什么。这可能是个错误。 Forth 有许多有趣的事情可做,硬件可就不这么有趣了。
我不知道你是不是听过这些历史,第一个 Forth 处理器是 Novix ,它也可能是所有这类处理器中的第一个。它是一个 16 位的处理器,使用高速工艺制造,平均 8MIPS 。这个工作很有趣,我们给它配了一个很好的 Forth 系统,称为 cmForth ,比我为 Forth Inc. 所做的其它 Forth 都更小、更简单,后来 ShBoom 是 32 位处理器, 50MIPS 。现在 i21 是最新的成果,它是 20 位的,我很高兴地宣布它的速度是: 500MIPS.
每个处理器都有它自己的 Forth 语言,目标非常简单:使硬件与软件结合的复杂性最小。只要我没有看到其它的人在做这件事情,只是嘴上说说的人不算,没有人真的在使复杂性最小方面做任何事情,那就是我需要尽力去做的。
我们正在建立一种文化,它不能够抗拒比如 Y2K 这样很小的灾难。一但我们失去了十亿美元的封装厂、一但我们失去了由数千人组成的程序员团队,我们还能够重新建立起来吗?不用关心能不能重建的事情?计算机值得我们的社会这样投入吗?它本来可以简单得多。如果它更简单,那么我对技术在未来不确定社会中更持久这样的事情就会更有信心。
把事情弄复杂好象是一个倾向。人们喜欢把它们弄得复杂,这种情况随处可见。你可以在电视节目中是看到,可以在市场的产品中看到,也可以在网站网页上看到,简单地表示信息不足,你把它弄得精彩。我想可能有一个最佳的复杂度是人脑能够设计它们。你把事情弄简单了,大众会觉得无聊,但是你把它们弄得太复杂,一样会失去大众。
我从来没有因为简单而觉得无聊。给我做一件事情更简单的方法,我就会迫不急待地去得到它。但是在汽车、飞机、航天器和大量的复杂设备方面却不是这样。 Forth 不需要这么复杂。经典的 Forth 是从简单开始的,它慢慢地被复杂所包围。在 Forth Inc. 里,这都成了公司的文化。我们有了一个软件包,我们销售它、我们拓展它、我们钟情于它。当我离开 Forth Inc 之后,就有了一个简化的机会, cmForth 就是成果。不幸的是 cmForth 并没有广泛应用,所以我很难告诉你它能够工作得多好。
在我的记忆中, ShBoom 与 cmForth 一样好。我做的最大应用是使视频能够工作并开始客户芯片设计包的过程,所以我知道使用 ShBoom 的捷径。
i21 ,我现在使用的是带颜色的 Forth ,还没有用它做有效的应用。它极端地简单,它比任何的前辈都简单。我想说说为什么。
i21 本身是一个简单的处理器,但也没有做到可能的最简化,因为好象我们能出售这个处理器的唯一希望就是它的速度,所以我增加了许多的复杂性以满足速度的要求。我希望我得到了某种平衡的理由。 500 MIPS 是一个诱人的速度。我们只能使这个速度保持片刻,但某一天它会变得平滑。问题是没有哪些应用需要这样的速度,或者说没有大量的处理器要求这种速度。它很难销售。
我最近已经看到的最有趣的应用是 SETI 的家庭计划,在这个计划中,你可以从 Arecebo 网站上下载数据并在自己的 PC 机上处理两个星期,然后把结果传回去与研究机构分享。所以一个快速的处理器可以很容易在那里销售和应用。可能 SETI 分布式处理器系统有一些事情可以做。
一但你得到了一个处理器,你希望它适合 Forth。之后, Forth 应该怎样开发这个处理器呢?这个问题引出了 Forth 是什么的问题。我期待有人能够告诉我答案。我不断在问, Forth 是什么?
Forth 是高度因子化的代码。我不知道除了说 Forth 是定义之外还能说什么。如果你有了许多短小的定义,那你就是在编写 Forth 程序。为了写出许多短小的定义,你需要一个堆栈。堆栈并不流行,我很奇怪为什么它没有流行。许多压力来自于既得利益者,他们不喜欢堆栈,他们喜欢寄存器。堆栈并不是能够解决所有问题的一个概念,但它的确非常非常有用,特别是对于信息屏蔽,并且你需要两个堆栈。
这些思想到现在已经有 30 多年了,我已经谈论它们 30 多年了,可现在被人们接受的程度与 30 年前没有什么差异,可能随着工业的发展,对它们的关注反而是更少了。
Forth
Defintions
Stacks
这就是 Forth 。需要支持定义。
什么是定义?非常经典的说法是一个定义就是用冒号说明一些事情、字、在什么地方结束定义等等
: some ~~~ ;
我总是试着通过缩写来说明其中的意义,不论你这里写下的字串是为了更常用或者是更方便。但它并不严格地是缩写,它可以有一个或者两个参数。这里有一个程序员相关的问题,也可能是与所有程序设计都有关的问题:我们给一个子程序输入了太多的参数。看看许多 C 语言程序,它们很可笑。程序中的每件事情都通过调用序列传递,而子程序只是一个哑巴。
一个 Forth 字不应该有多于一个或者两个参数。人们处理堆栈时有这么多的麻烦来处理堆栈,绝对不应该有多于 3 至 4 个元素的深度。
我们现在的具体做法是使一个字(:)以红色显示。通过这种方式你就不需要再使用冒号了,这不仅减少了你存储源程序文本的大小,而且也使得后面的工作极为清晰。红色的字是被定义的字:
some ~~~
定义是绿色的,在定义之中可以有一个分号表示返回,但是并不结束一个定义。如果需要,你可以有多个返回,你还可以有多于一个入口点。没有冒号定义,这个定义就会落入另一个定义,并在下一处返回;我们已经没有表示编译模式和执行模式的状态。你或者是在运行绿色或者是在运行白底黑字。黑色意味着执行,绿色意味着编译,红色意味着定义。
这对我来说更简单也更清晰,这是一个崭新的概念,但是还没有被广泛接受,不过我们马上就会看到。
但是对于堆栈来说,堆栈应该很浅。在 i21 芯片上,堆栈只有 18 个元素的深度,这个尺寸的选择是一个有效的数字。
处理这个堆栈的字是 DUP 、 DROP 和 OVER ,没有别的了。 SWAP 也很方便,你需要它,但它不是一个机器指令。但是,我们没有 PICK 和 ROLL ,没有什么复杂的操作可以使你能够按索引来访问元素。前两个元素是你需要关心的堆栈部分。当然。在一个芯片上,它们是两个 ALU 的输入端,这也是硬件相关的。
其它的元素也在堆栈上,因为你把它们放到了那里,你准备以后当堆栈回到那里时再处理它们。它们不在那里是因为你正在使用它们。你不想堆栈上的东西太多,因为你很快就会忘掉他们的意义。
所以,那些画堆栈图示的人马上应该明白他们正在做着不正确的事情,哪怕是很常用的短小的图示。这种方法是:如果你定义了一个字,你还写上一个说明来显示堆栈的影响,比如说 F 和 x 和 y
F ( x - y )
过去,当我把堆栈弄得太复杂时我也使用这种方法,但是现在不再这样了。我们不需要这类的信息,它应该能够从源代码中很容易地得到,或者应该在另外的地方编写文档。
所以我使用的堆栈操作非常有限,而条件操作也是这样,在经典的 Forth 中我们使用 IF ELSE THEN ,现在我排除了 ELSE 。
我不认为 ELSE 的用途能够与介绍它的复杂性相比较,你可以通过我的代码明白这一点。我将把 IF 和一个分号一起使用,我将在一个点上退出定义或者继续。
IF ~~~ ; THEN
我有两条分支,但是我用了“分号并不结束一个定义”的新特点。
还有循环,有许多循环结构。原来我使用的结构来自于其它的语言,我想事情就是这样发展的。它们是
DO LOOP 还有
FOR NEXT 还有
BEGIN UNTIL
DO LOOP 来自于 FORTRAN 语言, FOR NEXT 来自于 BASIC 语言, BEGIN UNTIL 来自于 ALGOL 语言。
我们在 Forth 中选择哪一个?这个 (DO LOOP) 有两个循环控制参数,太复杂了。这个 (FOR NEXT) 有一个循环控制参数,非常便于硬件实现,如果有足够的硬件实现时它本身也非常简单。这个 (BEGIN) 有可变数目的参数。不幸的是……(录像带杂音)
我们正在使用 iTV 的记录设备,这是它的拱顶 (vault) 。如果你听到了一个回音,那是什么?那就是拱顶。
我得到了一个新的循环结构,它在 COLOR Forth 中使用,我觉得它比另外的那些都好。这种方法是:如果我有一个字 WORD ,我可以实现对这个字 WORD 的某种有条件的引用。这就是我的循环方式。
WORD ~~~ IF ~~~ WORD ;
THEN ~~~ ;
我回到当前定义的开始 , 这就是我现在使用循环的唯一方法,它是足够而方便的。它还有两个边际影响:一个就是它要求一种递归版本的 Forth, 这个字必须在当前的定义中被引用,而不能够要求被预先定义。这就省去了 SMUDGE/UNSMUDGE 概念, ANS 正准备为这个概念找一个合适的名字。但是最终的结果是它更简单了。
对于嵌套的循环这种方法当然很不方便,但是嵌套的循环毕竟是一个不确定的概念。你也可以有嵌套定义。你应该条件化地执行一个字,还是应该有某种像 IF THEN 这样的结构?这个问题我们已经讨论 15 年了。这里有一个例子,我想它说得很明白,唯一的循环是必须重复一个字。
WORD ~~~ IF ~~~ WORD ;
THEN ~~~ ;
如果你这样坚持做下去,能够实现更彻底的因子化。这是我头脑中的 Forth 的关键,你因子化、再因子化、再因子化,直到你的大多数定义都只有一行或者二行长。
(Jeff) 你也许指的是 WORD 之后的那个分号导致一个尾递归,可以把对 WORD 的调用转为跳转。
(Chuck) 所以你没有理由进行一个调用,因为之后你不会到任何一个地方,你用一个跳转就可以了。实际上在我最近所有的 Forth 中,像分号一类操作的意义究竞是一个返回还是一个跳转将依赖于上下文,其中的优化是由编译器完成的。那是一个很简单的回朔优化,实际上是节省了重要的资源,那就是返回栈。
在我的 i21 中,返回栈的深度中只是 17 个,使用这种嵌套结构的人可能会遇到麻烦,你不能嵌套得太深,使得不可能再进行下一步的程序设计。你也可以使用调用来得到像使用 GOTO 一样的乱七八遭的代码。你应该保持简单。
这就是我能想起来的最近 Forth 所做的主要修改。可能 BLOCK 是个例外。 BLOCK 是一个有趣的块访问字,用于访问磁盘的一个区。现在我把它定义成访问存储器的一个区。没有任何理由使用磁盘了,由于有了兆字节级的存储器,你只需要把数据装入存储器,并从那里运行就可以了。由于需要磁盘, BLOCK 这个字就变得非常非常地简单,基本的 BLOCK 定义是一个与 1000 的积:
BLOCK 1024 * ;
这就指定了你访问的存储器是 1024 字节宽。 BLOCK 的值是你为存储器所做的分区值,它把你的存储器因子化成可管理的片断,你可以认为存储器是由一个兆字节所组成的,也可以认为是由几千个块所组成的。
我看过 NASA 的一个网页,现在想起来还很有趣。它说宇宙飞船的速度是每小时110,000 公里。因为我对这样的数字没有什么感觉,觉得如果把它转换成每小时69,000英里可能就会好一些。不过,这些数字对于普通人来说还是没有什么意义。我想应该把它转换成每秒多少公里或者其它我们能够感觉到的更小的数字。当我们使用 120M 字节的存储器时,使用这么大的数字不会有什么好处,它只不过是一个很大的数字而已,虽然令人印象深刻,但并没有什么用。所以 BLOCK 可以为我们进行适当的定标。
一个说法是 Forth 完全由程序员来决定。我愿意把这理解成 Forth 程序员应该做些什么。我发现教给了某人 Forth 语言,并不意味着他就是一个很好的 Forth 程序员了。在你能够进行有效的工作之前,有一些 Forth 形式和语法之外的东西已经嵌入到你的头脑中了。
我的观点是:我看到的每一个应用,只要不是我自己写的,它的代码量就会是它实际需要的 10 倍。我也看到 Forth 程序员正在用所需要代码量的 10 倍长的代码来编写应用程序。
我所关心的,我这几年一直深思的问题是:我怎么才能说服这些人编写好的 Forth ?我怎么才能告诉他们说编写好的 Forth 程序是可能的?为什么人们编写的程序是他们需要编写的 10 倍?
微软是这样做的,我想大家都知道,但是他们至少还有一个理由就是他们必须与任何以前所做的事情相兼容。如果你不能从一张清晰的白纸开始,那么你就得写更多的代码。但是需要 10 倍的代码吗?好象是太多了。
一个程序应该有多大?例如, TCP/IP 协议栈应该有多大?我不知道。在我坐下来编写代码之前我不知道。但是它不应该很大,大约 1K 字就可以了。
i21 的每个字有 4 个指令。奔腾计算机每两个字节一条指令。这很难判断。你应该讨论指令而不是指令驻留的存储器的大小。
看来大约有 1000 条指令就能够让我做任何事情,所有的程序都应该是 1000 条指令长。
你怎么做得到呢?这里面有什么诀窍?你怎样使应用程序很小?这里有几件事情是在任何情况下、使用任何语言都应该小心地去做的:
没有钩子
第一件事就是没有钩子。不要留一个接口,想着未来的什么时候当问题变化时插入一些代码,因为问题会以你不能预见的方式变化。反正这个成本肯定是浪费了。不要预测,只解决你眼前的问题。
不要复杂化
简化你遇到的问题,至少不要使它变得复杂化。我自己就是这样做的,很有趣。你遇到了一个令人厌烦的问题,在它之后是一个更有趣的问题。所以你应该为更有趣的问题编写代码,你所遇到的只是它的子集,它是微不足道的。但是,如果你努力地为这种微不足道的问题编码,那就当然地为你所需要解决的问题编写了相当于实际需要 10 倍的代码。
10 倍的代码意味着 10 倍的成本;编写的成本,文档的开销,存储器的开销,磁盘的开销,编译的开销,装入的开销。你所做的每件事情都要贵 10 倍。实际会更坏,因为复杂度是按指数增加的。
10x 代码
10x 成本
10x 错误
10x 维护
10 倍的错误! 10 倍的维护困难在 Y2K 问题上给出了很好的说明。奇怪的是我看到人们都在用 COBOL 解决 Y2K 问题,把程序明显地变得更复杂、更大、引入了更多的意大利面条式的代码,这些代码更不可维护。如果他们是使用 Windows ,那么 50 年之后,应用会再次崩溃。程序员们并不是扩大日期的范围,而只是移动它,所以在 Windows 运行到尽头的时候,它就会产生另一个问题。
这就是我们至今还在运行 10 年或者 20 年前老程序和为什么人们没有钱去更新、理解和重新编写这些程序的原因。因为它们太复杂了,比它们本来所应该有的程度复杂了 10 倍。
所以,你如何避免这个陷阱?你如何编写 1 倍的程序?
1 倍, 1x 应该是一个网页的名字
你因子化、因子化、因子化、因子化,你扔掉了所有不使用的东西、不合理的东西。
Forth 的全部在于你不能用 Forth 来编写程序,而是用 Forth 来编写字典。当你设计一个应用的时候,你写出 100 个左右的字,它们可以描述应用,然后你使用这 100 个字写出一行定义来解决应用的问题。找到这 100 个字并不容易,但它们是存在的,它们总是存在的。
让我给出一个应用程序的例子,在这个例子中你不仅能够减少 90% 的代码,而且有一个情况可以减少 100% 的代码。这个例子就是我们熟悉的文件。如果你在应用或者 Forth 系统中使用文件,你差不多有这样一些字:
OPEN CLOSE READ WRITE REWIND 等等
它们可能不是这么短的字,比如,像在 Windows 中 OPEN-FILE 。如果你觉得这些都不需要,那你将节省实现文件系统代码的 100% 空间。文件系统在一个典型的应用程序中并不是一个大个子的部分,但它是一个不常见的无用部分。确定了你要做的方面,说出了我们不需要做事情。我们不需要在校验和顶上再来做一次校验和。我们不需要编码加密因为我们根本就不需要传输任何东西。你可以省去所有这些事情。
你现在看到的是一个全世界所有的程序员所遇到的所有问题的一个解,这个解是通用的,但是没有任何人会遇到通用的问题。
我希望我告诉你的话能够使你写出好的 Forth 。我可以证明。我已经证明了应用程序代码可以减少 90% ,在某些情况下可以减少 99% ,我可以做,但是需要一个案例一个案例地做。我一直找不到一般性的原理。
(Jeff) 我有一个问题是有关你 COLOR Forth 屏幕的。人们已经注意到你在屏幕上使用了很大的字体,但是只有较少的信息。它多少是由于你的视力?你每次看的时候有多少的信息受到限制?
(Chuck) 我对小字体越来越没有耐心,几乎不能阅读网页。直接去看那些字符模糊不清,戴上眼镜看,它们还是模糊不清。如果加大字体,这有时能够做到,有时做不到,会失去一些上下文。这是一个问题,可能对于大众中不断增加的群体来说都是一个问题。所以我尽量地使用大的字符,但是如果你把它们弄得太大,那你就会丢失信息。
现在一个用于设计幻灯片翻页的经典规则是你拾取一帧然后在其中放入一些主题,你不能在一张幻灯片上放太多的内容,否则你的听众就会糊涂,如果你使用太小的字符,人们就不可能阅读这些内容。
在 COLOR Forth 的情况下,我想字符也可能太大了。我可以一次在一个屏幕上得到 256 个字符。根据所使用计算机的不同,我可以得到 20x14 或者有时是 24x15 。这就足够了。在 256个字符中,我得到的信息大约与过去 1024 字节得到的信息一样多,因为我没有进行格式化,甚至没有任何的换行。在我的屏幕上充满字符。
一个原因是我想探究彩色字的价值,如果我有一些带颜色的字,那么不同的颜色将如何工作?我发现它们做得好极了,我不需要用定义字来格式化它们。当然,实际上并不好看,因为在屏幕的左边好象有一个红墙,如果你也使用这种方式,那就不一定非使用红色不可。
我觉得你在做一个网页时也应该使用这种哲学。在网页上放入尽量少的信息,只要能把你想告诉人们的事情说清楚就可以了,不要弄得费话连篇。另一方面是不要在页面上放一个索引。你只应该放入真实的信息,你需要把重要的信息加亮,你需要使它清晰和可读。
要改变我的字体比较困难。我使用 32x32 像素点。下一次我可以使用 24x24 像素点试一试。
这种格式的应用程序很少是一个屏幕。一个应用程序大约是 2 个或者 3 个屏幕长,这与我在一个上下文中为一个应用程序所写的代码相当。
例如,我有一个应用程序,它把一个特殊芯片性能的谱显示在屏幕上。这是一个漂亮的显示,对于把信息表示成可理解的方式是一个很好的练习和重要的方法,如果以后你有机会看到它的演示,那一定是很有趣的。
小的应用程序。应用程序不是适当的字,小的代码只做特别的事情,从来都不做通用的事情。
Jeff 使我想起了 Machine Forth 的另外一些概念。 Machine Forth 是一个我很愿意回忆的 Forth ,它使用在机器中构建的 Forth 原语来做一些事情而不是使用解释器版本或者宏定义来做这些事情。这些事情之一就是 IF 。
经典的 IF 去除留在堆栈上的东西,这在 i21 上实现并不方便,所以 IF 把它的参数留在堆栈上,于是你就不得不经常写类似 IF DROP 这样的结构,但也不总是这样,看起来似乎方便和不方便各占一半。它不再使用 DUP IF 或者 ?DUP ,也就是说有了这种方便性,就不用 ?DUP 了。 ?DUP 并不是个好词,它在堆栈上留下了不同数目的东西,做这样的事情很不明智。
IF
-IF
除了 IF 之外, Machine Forth 还有一个判断 -IF 。这个字用于测试 0 ,那个字只用于测试符号位。我想你可能经常需要根据一个数是正还是负的来进行决策。但它并不是以那种方式工作的。在 COLOR Forth 中,我甚至不关心它怎么使用。
在过去的二十年中,世界已经发生了明显的变化,但我想没有人能够预测出来,当我 50 年代第一次开始工作时,只有 7 台用于计算的计算机。那时的计算机总是用来解决又大又长的算术表达式。我们所做的因子化工作就是把这些事情因子化,使得这些不必重复计算,它就可以运行得更快,那就是 FORTRAN 语言的全部观点。这种传统甚至到了今天还在影响着我们。
我没有做过统计,但是我猜想今天的计算机,绝大多数都不是用来做计算的,而是在移动字节。如果你有一个浏览器,这个浏览器除了一次性地计算机屏幕的大小外,几乎不进行什么计算。查看一个数的符号的概念可能并不像我想的一样有用,几乎所有的数都是正数,并不需要查看它们的符号。基于同样的原因, Machine Forth 没有减法操作。我把减法处理成 1 的补码。
- one comp
这种做减法的方式并不方便。但是对于今天的应用来说,实现协议或者显示文本,算术运算是不需要的。一个计算机不应该为算术运算进行优化,我的计算机也不是。
另一方面,为了数据传输方面的优化,实现一个增量存取操作就很有用。地址是在任何计算机上都有的问题,但在 i21 上这是一个更特别的问题。在 i21 上,地址是一个 20 位的数,为了装入一个地址,你最好做一个文字常量的取,它可以取出 20 位的扩展字。需要一个附加的存储器装入周期,之后你可以进行存储器读取,这又需要另外一个存储器周期。所以地址的处理非常昂贵,你应该尽力使它最小。取加 (@+) 操作字对此有所帮助。你把一个地址放入地址寄存器中,然后它就存在那里。如果你执行 @+ , A 将被增量,你就可以连续地读取后面的内容了。同样,你也可以存入一串东西。当然在需要的时候,你还有不进行增量的取 (@) 和存 (!) 操作。
在经典的 Forth 系统中并没有这些操作,我想在标准中也没有提及。它们导致了一种完全不同的程序风格。在 DO LOOP 的情况下,最有效率的事情就是把实际的地址作为循环参数,然后通过字 I 读出它,在循环内部进行对 I 的取 (I @) 。 DO LOOP 与地址一起工作,如果你做这些,如果你使用读加操作 (@+) ,那你就不需要 DO LOOP 了,你也不需要 I 了,你在循环中使用读加 (@+) 就可以每次读出不一样的事情,它们不同但是等效。你可以把一个转换成另一个,方便地读取那些地址在 A 寄存器中的东西。
在 MOVE 的情况下,你想把某些东西从存储器的一个区域移动到另一个地方,你就需要两个地址,因此作为地址的值存储在 R 寄存器中,因为只有在一个上下文中你才可能把地址放到 R 寄存器中,它有一个自动增量能力。所以我基本上有对于 A 的取加 (@+) ,对于 R 的取 R 或者存 R ,你可以有效地进行 MOVE 。
这就引出了另一个问题。 A 除了作为地址寄存器使用外,它还非常像一个局部变量,你可以在其中存一些东西,过一会儿再读出来。把它作为一个地址寄存器的原因和我使用它的原因是一样的,从字面上讲,它为地址访问提供了一个机制( (@+) 。从程序员的角度看,它比放在堆栈上的地址更方便。但是如果你准备反复地访问这个寄存器,就必须把它放在一个你可以对它进行增量的地方。为了放置它你必须访问那个寄存器,如果你能够做到这些,你就可以使用这个寄存器做别的事情,就像你使用返回栈做别的事情一样。
不同之处是如果你把一些东西放到返回栈上,还必须记着把它拿下去,对于 A 寄存器就不用这样了。有人试着把 A 作成一个堆栈,使得你可以把一些东西 PUSH 进去或者 POP 回来,是不是值得这样做并没有一个明确的答案。肯定需要更多的指令去访问 A 。你希望 DUP A ?你需要 DROP A ?现在这种 A 的方式是最容易的。
我也许还需要一个寄存器称为 M ,可以在 40 位的乘法中保存一个乘数。但是我的系统中并没有足够多的乘法要做,所以这件事还没有成为现实。
但这样一个寄存器却引出了一个局部变量的问题。有许多关于局部变量的讨论,这是在你的应用中能够节省 100% 代码的另一个方面。我坚信局部变量不但没有用,而且很有害。
如果你正在编写需要使用局部变量的代码,那么你就是在写……非优化的代码?不要使用局部变量。不要出现新的语法来描述它们,不要出现新的策略来实现它们。如果你有局部寄存器你就可以使得局部变量很有效,但是不要这样做。它不好。它是错误的。
变量是必要的。 COLOR Forth 需要许多的系统变量,当你编辑某些东西的时候,光标位置变量也非常有用。当你回到光标位置的时候,因为变量的值还在那里,所以你就能够回到原来的位置。变量很有用,我没有看到任何只使用少数变量的情况,也没有看到使用瞬时访问变量的情况。
聪明、解释堆栈图、给一个字命名,这些都是练习。你可以进行所有这些游戏。我想 Forth 程序员可能用他们已有的工具进行了太多这方面的游戏,因为没有应用。如果一个 Forth 程序员能够更多地关注应用程序而不是更新工具,那就更好了。
对于我来说,一个应用程序就是 Web 浏览器。如果你无事可做,那就写一个浏览器。 Netscape 并没有完成这件工作,没有做到它应该能做到的样子、没有实现它应该有的功能,。事实上 Netscape 和 Microsoft 都从 Mosaic 那里借用了大量的东西,它们看起来就像是孪生的东西。如果还是用同一种语言编写的,那种语言就是 FORTRAN 。
写一个新的浏览器。这是一个很好的应用。它能够使你访问信息世界,我将在业余时间关注这个好应用。
感谢各位的收听。