设计一台指令集计算机!


31

注意:我愿意悬赏任何我认为有趣的答案。

您的挑战是设计一台图灵完整的 指令集计算机(OISC):

OISC是一种仅使用一条指令的抽象机-无需使用机器语言操作码。通过对单个指令的明智选择和给定的无限资源,OISC可以像具有多个指令的传统计算机一样,成为通用计算机。

是构成图灵完整OISC的单个命令的一些示例。

规则:

您必须提供解释或证明

您必须为您的语言提供翻译。该解释器应仅受内存/时间限制(例如,必须没有用户施加的限制)。如果您没有为您的语言提供口译员(出于懒惰以外的其他原因),则必须证明可以编写该语言。口译员必须是可能的

您必须证明其图灵完备性

您必须提供正式证明,证明您的语言是图灵完备的。一种简单的方法是证明它可以解释或具有与另一种图灵完备的语言相同的行为。要解释的最基本的语言是Brainf ** k

例如,具有与Brainf ** k相同的命令(并且同样没有用户施加的内存限制)的普通语言是图灵完备的,因为可以在Brainf ** k中实现的任何内容都可以用该语言实现。 。

是非常易于实现的图灵完整语言的列表。

其他OISC要求

  • 该OISC应该只有一条指令-不能有多条指令,其中一条使图灵完成。

  • 您的OISC可以使用您喜欢的任何语法。您应该在答案中定义什么是指令,什么是数据以及什么是无操作(例如,空格)。有创造力!

  • 参数不仅需要是整数。例如,///是图灵完备的OISC的一个漂亮示例。

  • 如何以及是否进行输入和输出取决于您自己。大多数OISC通过特定的内存位置实现I / O,但可能还有其他方法可以实现,因此建议您找到一个。

  • 一个有效的答案必须在您的OISC中提供一些示例代码,方法是将其包含在帖子中,或者链接到使用该语言解决的简单挑战。

表决

选民,请记住不要反对无聊的意见。例子:

  • Lenguage -equivalents
  • 现有OISC的实现(答案,请创建您自己的!)
  • “ OISC”,其中第一个参数指定要调用的命令(示例

但是,您应该推荐有趣的创意作品,例如:

  • 基于数学方程式的OISC
  • 基于神经网络的图灵完备ZISC
  • 一个OISC,其中输出I / O以不同于某些内存位置的其他方式发生

获奖

,得票最多的答案将赢得胜利!祝好运!


10
什么是“指令”?以及我们如何计算它们?
小麦巫师

1
@NoOneIsHere我希望我知道足够去投票给xD
Brian H.

2
我对此表示反对。我认为这是一个非常有趣的想法,但是您无法确切说明OISC是什么,以及如何确认某物是一个。我将BF设为OISC,但这显然违背了问题的精神,但在技术上是有效的。
NoOneIsHere

1
@MDXF我不认为您/// ::它具有替换命令,并且具有打印命令,这不仅仅是替换命令的副作用
Destructible Lemon

1
@NoOneIsHere因为人气竞赛。是的,它是有效的,但得分很低(投票支持),因此不会赢。
user202729'2

Answers:


20

XOISC

该OISC基于福克的X组合器,其定义如下:

X=λf .f (λg h x .g x (h x)) (λa b c .a)

如果我们承认SKI演算是图灵完成的,则上述组合器也就是图灵完成的。这是因为SKI可以用X表示,如下所示:XSKIX

S=X (X X)K=X XI=S K K=X (X X) (X X) (X X)

XOISC如何工作

XOISC内部具有一个(最初为空)堆栈,从那里开始,以为参数的指令执行以下操作:n

  • 从堆栈中弹出元素(函数f 1f N),然后按f 1nf1fNf1 (f2 ((fN X)))

一旦没有更多的指令,XOISC会将所有命令行参数(如果有的话)推入堆栈,例如:

[s1,, sMstack before, a1,, aNarguments]

最终计算将为((((s1 s2)) sM) a1))aN


由于XOISC中的一条指令仅采用一个参数(内存偏移量),因此没有理由甚至为该指令使用名称。因此,有效的源文件将仅由用换行符或空格分隔的整数组成,例如:

0 0 2 0 1 0 1

在线尝试!

让我们以上面的示例为例(堆栈向右扩展):

0pop 0 and apply (ie. push single X):[X]0again simply push X:[X, X]2pop 2 (a,b) and push a (b X):[X (X X)]0simply push X:[X (X X), X]1pop 1 (a) and push a X:[X (X X), X X]0simply push X:[X (X X), X X, X]1pop 1 (a) and push a X:[X (X X), X X, X X]

最后评估堆栈:或带较少括号的X X X X X X X ((X (X X)) (X X)) (X X)X (X X) (X X) (X X),我们认为这是旧的标识功能。S K K

图灵完整性

证明思想

为了使XOISC完全图灵化,我们需要能够翻译任何(有效)括号和组合符的交织。这是可能的,因为在弹出,应用和推动时,它是以右关联的方式进行的(功能应用是左关联的)。X

要转换任何这样的表达式,有一个简单的方法:总是弹出尽可能多的元素,以便从当前括号级别的开头开始只剩下一个元素。X

例如,先前使用的表达式:((X (X X)) (X X)) (X X)

  • 要获得,我们只需要一个X0
  • 下一步,我们将圆括号放到新的高度,因此我们只需要一个 0
  • 现在两个圆括号都关闭了,所以我们需要弹出2个元素: 2
  • 同样,我们处于新的括号级别,因此我们需要 0
  • 两个括号,再次闭合 2
  • 并再次相同

因此,我们最终得到了一个不同的(但在语义上等效的)XOISC程序:

0 0 2 0 2 0 2 在线尝试!

如果我们坚持这种策略,我们可以轻松地转换任何由X组成的表达式X坚持组合器为XOISC程序,该程序仅在堆栈上保留一个函数。

正式证明

鉴于SKI演算已经完成了Turing,我们需要展示两件事:

  1. X -combinator是用于SKI-演算的基础
  2. XOISC能够表示由组合器形成的任何表达式X

第一部分-证明引言中的三个相等性-非常繁琐且占用空间,也不是很有趣。因此,您可以在此处找到*

第二部分可以通过结构归纳来证明,尽管更容易证明一个稍微强一点的语句:即,对于形成的任何表达式X组合器都有一个程序可以将该表达式作为单个表达式保留在堆栈中:

XXf gfg

0XF1FNG1GKfgf g

F1FN G1GK1 (GK+1)fggff g留在堆栈上。∎

口译员

输入项

由于无类型的lambda演算需要我们为所需的所有内容定义自己的数据类型,因此解释器意识到教会数字很麻烦。 -这意味着当您提供输入时,它将自动将数字转换为相应的教堂数字。

例如,下面是一个将两个数字相乘的程序:在线尝试!

您也可以使用De Bruijn索引(例如,S组合器\\\(3 1 (2 1))(或λλλ(3 1 (2 1))))将函数作为参数提供。然而,它也承认SKI当然X组合子。

输出量

默认情况下,解释器检查输出是否编码为整数,如果输出,它将输出相应的数字(除结果外)。为了方便起见,有一个-b标志告诉告诉解释器尝试匹配布尔值(请参见最后一个示例)。

组装工

当然,任何低级语言都需要将高级语言转换为该语言的汇编器,您可以简单地使用任何输入(请参见上文),并通过使用-a标志将其转换为XOISC程序,然后在线尝试!**


*如果链接断开,这篇文章中会有一个副本作为HTML注释。

**这会产生一个测试素数的程序,请在线尝试!


1
您选择X组合器而不是Iota组合器是有原因的吗?
Esolanging Fruit '18

1
@EsolangingFruit:是的,还有其他几种选择,最后我选择了那个,因为它使用最少的应用程序来构建SK。看来它会表现最好(我自己还没有做比较)。
ბიმო

1
顺便说一句。如果您有兴趣,可以在链接的论文中对几种组合器进行很好的比较。
ბიმო

19

Draw是一个作用在2D网格上的OISC,以类似于Wang B机的方式标记正方形。但是,为了使语言尽可能简单和OISC-y,所有指令(总共一个指令)都标记刚踩过的正方形,并且为了能够停下来,踩到一个标记的正方形终止程序。

该程序由一系列行组成,这些行包含一个行标识符(不包含#或空格的任意字符串),两个整数(xy)和另外两个行标识符(ab)。

程序运行如下:
从标识为的行开始,start指针指向位置(0,0),将指针移动由x和给出的量,y并标记指针现在所在的正方形(除非已经标记了正方形,在这种情况下,执行会终止)。然后,a如果还标记了至少一个直接相邻的正方形,则跳到行,否则跳到行b

鼓励口译员将网格的最终结果输出为某种图像,画布等。

图灵完成度

Draw是图灵完备的,因为可以将Minsky机器的修改版本(称为Alternate)编译为该语言。

Alternate的行为类似于两计数器Minsky机器,但是命令上有一个很大的限制:命令必须在定位第一个和第二个计数器之间交替。为了避免这种修改,添加了一个附加命令:nop。此命令完全不会更改目标计数器,这使得可以将连续的更改“填充”到一个计数器中,从而满足上述限制。这也意味着不必更改要修改的寄存器,并且对于任何给定的指令,都可以直接从执行跳转的指令中推断出来。

示例:这台Minsky机器

1 inc A 2
2 inc A 3
3 dec A 3 4
4 halt

变成这个备用程序:

1 inc 2
2 nop 3
3 inc 4
4 nop 5
5 dec 6 8
6 nop 5
7 halt
8 halt

由于最终的Draw程序处理寄存器的方式是必要的,因此必须完全不区分它们。取而代之的是,Draw程序只是复制前一条指令未更改的寄存器,并根据正在执行的指令对其进行修改。

然后,将Alternate程序直接转换为Draw,如下所示:

程序从该块开始。

start 0 0 a a
a 3 0 b b
b -3 1 c c
c 3 0 d d
d -3 2 e e
e 3 0 f f
f 3 -3 i1_a i1_a

incdec并且nop彼此之间的翻译方式几乎相同。在所有情况下,更改第一或第二寄存器之间没有区别(如上所述)。这是一个增量,等效于inc 2

i1_y 0 -2 i1_z i1_y
i1_z 3 -1 i1_a i1_a
i1_a -5 1 i1_b i1_b
i1_b 0 2 i1_c i1_c
i1_c 0 2 i1_d i1_e
i1_d 0 2 i1_d i1_f

i1_e 5 0 i2_z i2_y
i1_f 5 0 i2_z i2_y

i1_x部分中的数字更改为当前指令的索引,并将部分中的数字更改i2_x为要执行的下一条指令。

nop指令可以这样翻译:

i1_y 0 -2 i1_z i1_y
i1_z 3 -1 i1_a i1_a
i1_a -5 1 i1_b i1_b
i1_b 0 2 i1_c i1_c
i1_c 0 2 i1_d i1_e
i1_d 0 2 i1_d i1_f

i1_e 5 -2 i2_z i2_y
i1_f 5 -2 i2_z i2_y

这是一个递减:

i1_y 0 -2 i1_z i1_y
i1_z 3 -1 i1_a i1_a
i1_a -5 1 i1_b i1_b
i1_b 0 2 i1_c i1_c
i1_c 0 2 i1_d i1_e
i1_d 0 2 i1_d i1_f

i1_e 5 -2 i3_z i3_y
i1_f 5 -4 i2_z i2_y

i3_x 如果计数器已经是1,则指要调用的指令。

停止:

i1_y 0 0 0 0
i1_z 0 0 0 0

适当地更改标签,并将所有内容简单地链接在一起。从上面的示例开始执行此操作,从上方给出了存储库中的Draw程序。

口译员

当前有两个解释器,都用Python编写。可以在Draw的GitHub存储库中找到它们。

  1. draw.py:此解释器用于命令行,并以程序源作为参数。每一步之后,它输出已执行的命令和指令指针的位置。程序停止后,它会打印已标记单元格的数量。
  2. draw_golly.py:此版本使用Golly进行错误的目的更简单的图形输出,在启动脚本时通过弹出框获取源代码。Golly对于Python可能有点挑剔,因此请确保您已安装Python 2(并且不要将32位Golly与64位Python混合使用,反之亦然)。输出通过Golly的内置单元格网格提供。

下图是第二个解释器输出的示例。在存储库中运行示例程序将得到以下信息(或类似信息):


1
惊人!祝贺您找到了一种非常独特的方式来应对挑战。
MD XF

您的语言不需要完全停止就可以完成。规则110并没有终止,但是仍然完整。
Akangka

为Golly +1最佳蜂窝自动机模拟器。
高度放射性的

14

-3

这是要点。

记忆

内存是磁带的映射,键是字符串,值是任意大小的整数。

此外,还有一组标签,程序可以跳转到这些标签。

有一个堆栈,其中包含操作数,它们是字符串。

有一个问题,它控制着它可以访问内存中的磁带。

一条指令

-。首先,它从LABEL堆栈中弹出一个字符串。如果未将LABEL其定义为标签,则它定义标签,并清除该标签的来源(即从何处被推送)和当前指令。否则,它将使用前两个值A和执行以下计算B

if mem[A] < mem[B]:
    jump to LABEL
if mem[A] != mem[B]:
    mem[A]--
else:
    mem[B]++

请注意,如果有过多的参数或参数不足,程序将出错,显示程序的状态。

可以通过访问的值来修改偏移量.

范例程式码

X-

i i X-
i i X-
i i X-
i i X-
i i X-
i i X-
i i X-

通过增加时间将变量设置i为。77

X-

i i X-
i i X-
i i X-
LOOP-
    a a X-
    a a X-
    j i LOOP-

这乘以i+1常数2

图灵完整性证明

忽略C ++的int大小(也就是说,假设它们是无限的),通过减少为3单元Brainfuck,-3是Turing Complete 。我可以忽略此大小,因为可以在具有无限大内存且具有任意大单元的计算机上为-3编写解释器。

我也相信任何BCT都可以编写为-3程序。


正如我喜欢提高我的内容,请有关下来解释投票,将不胜感激
康纳尔奥布莱恩
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.