正文

1x Forth (2)2005-08-05 13:28:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/forth/3450.html

分享到:

还有循环,有许多循环结构。原来我使用的结构来自于其它的语言,我想事情就是这样发展的。它们是

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% 空间。文件系统在一个典型的应用程序中并不是一个大个子的部分,但它是一个不常见的无用部分。确定了你要做的方面,说出了我们不需要做事情。我们不需要在校验和顶上再来做一次校验和。我们不需要编码加密因为我们根本就不需要传输任何东西。你可以省去所有这些事情。

你现在看到的是一个全世界所有的程序员所遇到的所有问题的一个解,这个解是通用的,但是没有任何人会遇到通用的问题。

阅读(3025) | 评论(0)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

暂无评论
您需要登录后才能评论,请 登录 或者 注册