高尔夫语言存储技巧


16

我正在写一种高尔夫球语言。

您是否建议使用代码高尔夫球语言存储变量,堆栈,磁带,寄存器等?隐式输入呢?

粗略定义:

  • 变量是简单地将一个值可以被分配到,后来由该名称检索的名(通常一个字符长在打高尔夫球的语言)。
  • 寄存器就像是一个可变的,但它有自己(通常是单字节),用于设置/获取的值的命令。
  • 堆栈是值,其中最近添加的值(“顶部”的值)是被改性的那些的可变长度数组/列表。
  • 队列是像一个堆栈,除“上的值底部 ”是正在修改的那些。
  • 是其中每个值具有索引值的静态数组/列表。堆栈和磁带之间的主要区别在于,磁带上的值是就地修改的。

我希望知道每种方案在不同情况下以及总体上的优缺点。请避免发表意见,并带有推理的备份声明。


1
我认为您应该在问题中包含这些术语的定义
Kritixi Lithos

2
@Fatalize从技术上讲,存储方法不取决于您正在制作的高尔夫球语言,高尔夫球语言的类型取决于存储方法...
ETHproductions'Apr

1
@ETHproductions它们是完全相互依赖的。
Fatalize

1
我为各种存储术语添加了一些粗略的定义,如果您不喜欢它们,可以随时进行编辑或回滚。
ETHproductions'Apr

2
存储方法和语言类型之间有非常密切的关系,但是我认为您必须同时考虑两者。例如,“命令式”语言(严格按照从左到右执行其指令的语言)可以基于堆栈(CJam,05AB1E),基于磁带(BrainF ***)或完全其他(V,使用一个大的2D字符串,称为“缓冲区”,以及一些寄存器。还有基于前缀的语言(Pyth),基于中缀的语言(Japt,Pip和基本上每个主流lang),基于链接的语言(Jelly)等,这些几乎都没有使用任何上述方法。
ETHproductions'Apr

Answers:


4

所有存储类型都涉及到将某物存储在一个点上,然后再取回它。若要仅在一个操作中执行此操作,则应自动存储或检索,并在另一操作中指定存储值的位置。

也就是说,对于显式存储,您可以创建一个运算符以在此操作之前检索第n个计算值,或在n次操作之后返回当前值。或者,您可以从程序开始使用绝对位置,或执行更多操作,例如在某些操作后自动删除某些元素(例如,在堆栈中)。您还可以创建多个运算符,无论是否具有这些自动操作,都可以从存储的不同副本中检索。而且,您应该尽量减少在操作中指定的最大数量,以便可以为每个数字分配一个运算符。

但是在大多数情况下,您甚至不需要运算符,并且语言会隐式地执行此操作。那就是当您需要考虑更标准化的模型(例如堆栈或队列)时。目前最成功的似乎是默认编程,它甚至没有直接提到存储。

如果要设计新的模型,则可以尝试将评估扩展为dag,如果未指定其他内容,则可以尝试考虑默认dag。最有可能的是,默认设置只是一棵树,除了可能将多个叶子链接到同一输入。例如,您可以将队列用于平衡树,或将堆栈用于叶子通常保持不变的深树,或将Jelly用作深度树,其中叶子主要是输入的副本。

但是请注意,每个运算符只可以对2位树的形状进行编码。因此,如果您的语言的运算符少于64个,则实际上您可能会忽略传统模型,而只是用备用位(将它们称为Combine_parent和below_leaf标志)对完整的树进行编码。即使有更多运算符,您也可以设置一个相当不错的默认值(例如Jelly模型)并使用3个修饰符对其进行更改。

为了方便起见,您可以将相同的模型用于隐式和显式存储,但不必这样做。例如,您可以将堆栈用于隐式存储,但不要在显式存储(或除隐式存储之外的其他显式存储)中弹出元素。在最终文档中可能不会将其称为堆栈,但是您可以理解。

作为参考,二叉树的完美编码大小是加泰罗尼亚数的对。“二进制” dag的完美编码的大小是A082161的对数,但显然不切实际。假设一个具有不同自变量顺序的运算符将两个不同的运算符排序,否则将另外一位加。

有时您可能仍需要循环变量。可能可以用其他方式重写循环。但是,如果您确实需要它,除了定义变量的名称外,不要使用1字节的结构。除非您仅使用预初始化的值,否则通常使用1位标志来指定您正在读取还是写入此变量更为有效。


7

我建议所有人!

更严重的是,它们有时会派上用场,而且越好越好!隐式输入从不,只要有一个标志将其关闭即可。变量很有用,因此不需要在堆栈或磁带上找到它们;与寄存器相同。堆栈对存储数据很有用,磁带也对存储数据有帮助。我建议尝试实现多个,例如堆栈寄存器,或者堆栈和变量,例如GolfScript。如果您可以将每个功能设置为一个字节,那么您的语言可能会在打高尔夫球方面很有效,因为您可以利用每个功能的优势。

一个例子:

  • 假设我想将两个数字作为输入,并添加其字符串长度
  • 变量可能对此更好(堆栈可能没有)
  • GolfScript中的示例代码(具有隐式输入):

    ~,\,+
    ~ # Eval input (e.g. "1 2" > 1, 2)
    , # Take Length
    \ # Reverse items on the stack
    , # Take Length
    + # Add
      # Implicit output
    

    但是,有了变量(我知道它更长了,它不必交换堆栈上的位置):

    ~,:a;,:b;ab+
    ~ # Eval input
    , # Get length
    :a# Store in "a"
    ; # Discard value left on stack
    , # Length
    :b# Store in "b"
    ; # Discard
    a # Recall a
    b # Recall b
    + # Add
      # Implicit output
    

超载

另一件事可能是有用的是重载。例如,如果您具有变量存储功能,则可以将其用作monad(单输入功能;我不确定J / K / APL之外的术语)可以添加到堆栈或磁带中。

例:

c12 # Stores "1" into register 2
c1] # Pushes "1" onto the stack ("]" is used to denote the end of the monad)

也许如果用错误的类型调用了一个参数,它将被添加到一个队列中,如果堆栈为空,该队列将用于填充值?
硕果累累

5

我建议您有一些快速可用的存储(来自给定的-磁带,队列,堆栈)和一些永久性存储(变量,寄存器),以防程序执行无关的操作时不会妨碍您。我想说的是,更多的东西很少会给出任何东西,而更多的字符可用于更多的1字节指令。

根据给出的定义,我认为效果最好的将是堆栈和寄存器。
堆栈,因为磁带必须使用仅用于在其中存储新事物的功能,而堆栈则应具有简单的推入和弹出功能(通常内置在命令中)。寄存器,因为与变量相比,它们通常占用较少的字节,并且如果您需要为某项存储2-4个以上的不同事物,那么您就在做错事情。

不要仅仅将它们的功能限制在其名称或定义所暗示的范围内-某些功能put the 1st thing of the stack on top of the stack肯定可以提供帮助。


5

基本上有两种存储需要不同的处理方式;访问最近生成的值和/或输入;和长期存储。

对于长期存储,变量似乎效果最好。选项数量有限的任何事物都无法扩展(尽管具有此属性的语言,例如Jelly,即使在中等大小的任务上也可以做得很好)。但是,在大多数情况下,存储变量时无需提供变量。只需有一条命令即可在变量中存储一个值,并根据可预测的模式自动生成名称,以便在简单情况下,存储和检索该值可以是一个命令。(例如,您可以使用命令来恢复最近分配的变量,第二个最近的变量,第三个最近的变量,依此类推,直到一个小的固定数字,再加上一个带有参数的通用命令。)

对于短期存储,您希望尽可能多地隐式存储。默认情况下,我见过的几乎所有高尔夫语言都将一个命令的输出连接到另一个命令的输入。确切的执行方法因语言而异,但通常是同一回事。但是,用于2输入命令的第二输入更为有趣。如果仅使用一次值,但在重用值时伸缩性不好,那么从堆栈中获取它的效果很好。(尝试避免堆栈操作原语;如果必须使用它们,则会浪费很多字节。)或者,使用用户输入或最近分配的变量作为隐式第二个参数往往会节省一些字节空间。简单的程序,尽管

使用目前正在使用的高尔夫语言,我结合了一种非常便宜的机制(一个)来指定解析树的形状,默认情况下自动填充用户输入中缺少的参数,并带有一个检查点这种方法可以将缺少参数的默认值设置为其他值(加上许多特殊情况)。在某个时候,我可能会添加变量以在程序中更远地传达信息。


0

我建议磁带和寄存器。

与磁带相比,我更喜欢磁带,因为磁带倾向于包含较少的元素,从而使它们的操作变得容易。同样,能够将元素放置在寄存器中的磁带中,反之亦然,这可以简化代码。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.