Concatenative languages具有一些非常有趣的特征,例如能够组合不同arity的函数并能够分解函数的任何部分。然而,许多人因为使用后缀表示法以及如何阅读而难以理解。此外,波兰人可能不会欣赏使用他们精心制作的符号的人。
那么,是否可以使用前缀表示法?如果是,那么权衡是什么?
我知道它是如何工作的,但我对连接语言没有经验,所以我可能会遗漏一些东西。基本上,将以相反的顺序评估函数,并且将以相反的顺序从堆栈中提取值。为了证明这一点,我将postfix与前缀的外观进行比较。以下是一些使用传统后缀表示法的连接表达式。
5 dup * ! Multiply 5 by itself
3 2 - ! Subtract 2 from 3
(1, 2, 3, 4, 5) [2 >] filter length ! Get the number of integers from 1 to 5
! that are greater than 2
从左到右计算表达式:在第一个示例中,5
被推入堆栈,然后dup
复制堆栈上的顶部值,然后*
乘以堆栈顶部的两个值。函数首先从堆栈中提取它们的最后一个参数:在第二个示例中,当调用-
时,2
位于堆栈的顶部,但它是最后一个参数。
这就是我认为前缀符号的样子:
* dup 5
- 3 2
length filter (1, 2, 3, 4, 5) [< 2]
表达式从右到左进行计算,函数首先从堆栈中拉出第一个参数。请注意前缀过滤器示例如何更准确地读取其描述,并且看起来与应用样式类似。我注意到的一个问题是将事物分解出来可能没那么有用。例如,在后缀表示法中,您可以从2 -
中分解3 2 -
以创建subtractTwo函数。在前缀表示法中,您可以从- 3
中分解- 3 2
以创建subtractFromThree函数,这似乎没有用处。
除非有任何明显的问题,否则使用前缀表示法的串联语言可能会胜过不喜欢后缀表示法的人。任何见解都表示赞赏。
答案 0 :(得分:3)
我现在正在编写这样一种语言,到目前为止,我喜欢使用前缀表示法的一些副作用。语义基于Joy:
这是阶乘函数,例如:
def 'fact [cond [* fact - 1 dup] [1 drop] dup]
我也发现在编写代码时更容易推理代码,但我没有强大的连接语言背景。这是我对列表中的map函数的(可能是天真的)推导。 'nb'函数会丢弃某些内容并用于注释。 'stash [f]'弹出一个临时值,在堆栈的其余部分运行'f',然后再次打开温度。
def 'map [q [cons map stash [head swap i] dup stash [tail dup]] [nb] is_cons nip]
nb [map [f] (cons x y) -> cons map [f] x f y
stash [tail dup] [f] (cons x y) = [f] y (cons x y)
dup [f] y (cons x y) = [f] [f] y (cons x y)
stash [head swap i] [f] [f] y (cons x y) = [f] x (f y)
cons map [f] x (f y) = cons map [f] x f y
map [f] [] -> []]
答案 1 :(得分:3)
当然,如果你的话仍然是固定的,那么只需要从右到左执行令牌。
这只是因为n-arity函数的前缀表示法意味着括号,而且只是因为想要人类“阅读顺序”来匹配执行顺序,因为堆栈语言意味着后缀。
答案 2 :(得分:3)
我刚刚阅读了关于Om Language
的文章似乎正在谈论的是什么。从它的描述(强调我的):
Om语言是:
- 一种新颖的,最简单的连接,同源编程和算法符号语言:
- 最小语法,仅由三个元素组成。
- 前缀表示法,其中函数操纵程序本身的其余部分。 [...]
它还声明它还没有完成,并且还会经历很多变化。
尽管如此,它似乎仍在起作用,并且作为概念证据非常有趣。
答案 3 :(得分:0)
我想象一个没有堆栈的串联前缀语言。它可以调用函数,然后函数会自己解释代码,直到获得所有需要的操作数。解释器然后会调用下一个函数。它只需要一个内存构造 - 结果。在执行时,可以从源代码中读取其他所有内容。你可能已经注意到了,我说的是解释语言,而不是编译语言。