如何在 Forth 中对参数进行排序
How to order the arguments in Forth
在 Forth 中定义单词时选择参数顺序的一般规则(经验法则)是什么?
比如控制几个舵机,我们定义SERVO!
来设置一个舵机通道的位置。
按照!
的方式,应该是: SERVO! ( val #ch -- )
,但是另一方面: SERVO! ( #ch val -- )
是不是更原生?
你提到的 : SERVO! ( val #ch -- )
的 !
方式可能是最好的,因为你不需要在计算你想要伺服的值时在精神上跟踪你正在使用的伺服搬去。
此外,由于它类似于 !
(您正在将一个值存储到伺服中),并且您将单词命名为 SERVO!
,如果参数顺序为!
.
相反
如何选择参数顺序?好问题!在 Forth 中,这个问题也应该包括结果的顺序。
显然任何规则都应该有一些基本原理。它们可能是一些基本原则的结果,或者应该解决一些问题。
我认为我们可以从方便代码重用(任何源代码片段,包括任何单个单词)开始。这种便利的基本正式部分是一致性和源代码最小化。
关于参数顺序这些部分具有以下含义。
- 一致性:相似的情况下应该使用相似的顺序(更正式的:在相似的情况下保留一些本质上的同构)。
- 最小化:我们应该选择一个最小化所有源代码的总词法大小的顺序(实际上,正确的顺序应该最小化堆栈操作的总数)。
因此,首先,我们应该与现有约定(或现有代码)保持一致,其次 — 找到最佳排序。当然,当在某些必需的旧代码中已经使用了不一致的约定时,可能会有例外。
一些已知的约定可以在 Leo Brodie 著名的“Thinking Forth”一书中找到。其中两个如下。
让地址先于计数。 (Tip 4.18)
示例:ERASE ( addr u -- )
让来源在目的地之前。 (Tip 4.19)
示例:MOVE ( source destination count -- )
还有一个众所周知的规则,既是约定又是优化(经过实践证实):
让不那么永久的争论先于更永久的争论。
通常它会导致更少的堆栈操作。这个规则可以在许多标准词中找到。例如,WRITE-FILE ( addr u file-id -- ior )
或 SEARCH-WORDLIST ( addr u wid -- 0 | xt flag )
— file-id
和 wid
比 addr u
对更持久。更多的永久参数倾向于保存在顶层变量中,因此更容易将它们作为顶层参数传递。示例:... GET-CURRENT SEARCH-WORDLIST ...
此规则也隐含地反映在 Leo Brodie 的以下提示中
- 在确定通过数据结构而不是通过堆栈处理哪些参数时,请选择更持久或代表当前状态的参数。 (Tip 7.3)
在结果的情况下,此规则变为相反。
对于退回的物品,让更多的永久物品在更少的永久物品之前。
例如,ior
、flag
等 — 通常返回顶部。
变化
在某些情况下,拥有多个变体会很方便。
例如,众所周知的单词 ROT
和 -ROT
。其他示例:
\ the different order of input paramenters
for-list-node ( i*x list xt -- j*x )
foreach-list-node ( i*x xt list -- j*x )
\ the different order of output parameters
split ( sd-txt sd-key -- sd-txt false | sd-left sd-right true )
split- ( sd-txt sd-key -- sd-txt false | sd-right sd-left true )
在 Forth 中定义单词时选择参数顺序的一般规则(经验法则)是什么?
比如控制几个舵机,我们定义SERVO!
来设置一个舵机通道的位置。
按照!
的方式,应该是: SERVO! ( val #ch -- )
,但是另一方面: SERVO! ( #ch val -- )
是不是更原生?
你提到的 : SERVO! ( val #ch -- )
的 !
方式可能是最好的,因为你不需要在计算你想要伺服的值时在精神上跟踪你正在使用的伺服搬去。
此外,由于它类似于 !
(您正在将一个值存储到伺服中),并且您将单词命名为 SERVO!
,如果参数顺序为!
.
如何选择参数顺序?好问题!在 Forth 中,这个问题也应该包括结果的顺序。
显然任何规则都应该有一些基本原理。它们可能是一些基本原则的结果,或者应该解决一些问题。
我认为我们可以从方便代码重用(任何源代码片段,包括任何单个单词)开始。这种便利的基本正式部分是一致性和源代码最小化。
关于参数顺序这些部分具有以下含义。
- 一致性:相似的情况下应该使用相似的顺序(更正式的:在相似的情况下保留一些本质上的同构)。
- 最小化:我们应该选择一个最小化所有源代码的总词法大小的顺序(实际上,正确的顺序应该最小化堆栈操作的总数)。
因此,首先,我们应该与现有约定(或现有代码)保持一致,其次 — 找到最佳排序。当然,当在某些必需的旧代码中已经使用了不一致的约定时,可能会有例外。
一些已知的约定可以在 Leo Brodie 著名的“Thinking Forth”一书中找到。其中两个如下。
让地址先于计数。 (Tip 4.18)
示例:ERASE ( addr u -- )
让来源在目的地之前。 (Tip 4.19)
示例:MOVE ( source destination count -- )
还有一个众所周知的规则,既是约定又是优化(经过实践证实):
让不那么永久的争论先于更永久的争论。
通常它会导致更少的堆栈操作。这个规则可以在许多标准词中找到。例如,WRITE-FILE ( addr u file-id -- ior )
或 SEARCH-WORDLIST ( addr u wid -- 0 | xt flag )
— file-id
和 wid
比 addr u
对更持久。更多的永久参数倾向于保存在顶层变量中,因此更容易将它们作为顶层参数传递。示例:... GET-CURRENT SEARCH-WORDLIST ...
此规则也隐含地反映在 Leo Brodie 的以下提示中
- 在确定通过数据结构而不是通过堆栈处理哪些参数时,请选择更持久或代表当前状态的参数。 (Tip 7.3)
在结果的情况下,此规则变为相反。
对于退回的物品,让更多的永久物品在更少的永久物品之前。
例如,ior
、flag
等 — 通常返回顶部。
变化
在某些情况下,拥有多个变体会很方便。
例如,众所周知的单词 ROT
和 -ROT
。其他示例:
\ the different order of input paramenters
for-list-node ( i*x list xt -- j*x )
foreach-list-node ( i*x xt list -- j*x )
\ the different order of output parameters
split ( sd-txt sd-key -- sd-txt false | sd-left sd-right true )
split- ( sd-txt sd-key -- sd-txt false | sd-right sd-left true )