📜  自然语言编程

📅  最后修改于: 2021-10-20 10:22:51             🧑  作者: Mango

用多种语言编程多年,我经常发现自己用英语伪代码思考,然后我将我的想法转化为我当时正在使用的任何人工语法。所以有一天我想,“为什么不简单地在自然语言级别编码并跳过翻译步骤?”我和我的大儿子(也是一名程序员)讨论了这个问题,我们决定测试这个理论。具体来说,我们想知道:

1. 当您不必将自然语言思想转换为替代语法时,编程是否更容易?

2. 自然语言能否以相对“草率”的方式进行解析(就像人类显然解析它们的那样)并且仍然为生产性编程提供足够稳定的环境?

3. 低级程序(如编译器)能否用高级语言(如英语)方便高效地编写?

因此,为了回答这些问题,我们着手开发纯英语编译器(纯英语)。我们很高兴地报告,我们现在可以从直接经验中回答这三个问题中的每一个,并且响亮地说:“是的!”

理论

我们相信,我们的解析器的运作类似于人脑中的解析中心。例如,考虑一位父亲对他的小儿子说……

“Want to suck on this bottle, little guy?”

……孩子听到了……

“blah, blah, SUCK, blah, blah, BOTTLE, blah, blah.”

……但他做出了正确的反应,因为他的头部右侧有一个瓶子的“图片”与左侧的“瓶子”这个词相连,而他脖子后部附近的一个预先存在的“技能”与“糟透了”这个词。换句话说,孩子把他能做的和他积累的图片(类型)和技能(套路)相匹配,其他的就不管了。我们的编译器做的事情非常相似,新的图片(类型)和技能(例程)被定义——不是由我们,而是由程序员在编写新的应用程序代码时定义。

实践

典型的类型定义如下所示:

A polygon is a thing with some vertices.

在内部,名称“多边形”现在与一个动态分配的结构相关联,该结构包含一个双向链接的顶点列表。 “顶点”在别处(在此定义之前或之后)以类似方式定义;复数是自动理解的。

一个典型的例程如下所示:

To append an x coord and a y coord to a polygon:
Create a vertex given the x and the y.
Append the vertex to the polygon’s vertices.

请注意,参数和变量不需要正式名称(专有名词)。我们相信,这是一个重要的见解。现实世界中的椅子或桌子永远不会(在正常对话中)称为“c”或“myTable”——我们将这些东西简单地称为“椅子”或“桌子”。同样在这里:“顶点”和“多边形”是这些变量最自然的名称。

另请注意,例程和变量名称中允许使用空格(如“x coord”)。令人惊讶的是,所有语言都不支持此功能;毕竟这是 21 世纪。另请注意,也允许使用“昵称”(例如“x”代表“x 坐标”)。并且所有格(“多边形的顶点”)以非常自然的方式用于引用记录中的字段。

还要注意,“给定”一词可能是“使用”或“与”或任何其他等价物,因为我们草率的解析侧重于理解所需的图片(类型)和技能(例程),而忽略了尽可能,其余的。

像一本数学书

在最低级别,事情看起来像这样:

To add a number to another number:
Intel $8B85080000008B008B9D0C0000000103.

请注意,在这种情况下,我们在单个例程中同时拥有最高和最低的语言——英语和机器代码(十六进制)。这里的见解是,程序应该主要用自然语言编写,根据(并且仅根据)需要使用更合适的语法的代码片段。就像一本典型的数学书:主要是自然语言,散布着公式片段。

我们希望有一天这项技术能够扩展到高端,包括普通西班牙语、普通法语和普通德语等;并在低端包括最有用的、特定领域语言的“片段解析器”。

异议得到答复

现在也许您认为自然语言编程是一个愚蠢的想法。但是您是否考虑过这样一个事实,即大多数程序中的大部分代码做一些简单的事情,例如“将其移到那里”和“将其显示在屏幕上”——这些事情可以用自然语言最方便、最自然地表达?让我们考虑一个可以详细检查的示例:

我们的编译器——一个复杂的普通英语到可执行机器代码的翻译器——有 3,050 个祈使句。

其中 1,306 个(约 42%)是条件语句,其中至少有一半是像这样的琐碎事情:

If the item is not found, break.
If the compiler's abort flag is set, exit.

这些条件语句的其余部分稍微复杂一些,但它们都适合在一行中。以下是一些较长的:

If the length is 4, attach $FF32 to the fragment's code; exit.
If the rider's token is any numeric literal, compile the literal given the rider; exit.

剩下的句子中:

272(约 9%)是简单的赋值语句:

Put the type name into the field's type name.

202(约7%)只是各种循环的基础设施:

Loop.
Get a field from the type's fields.
[ other stuff here]
Repeat.

183 (6%) 只是在这个或那个列表的末尾添加一些东西,如下所示:

Add the field to the type's fields.

164(大约 5%)是用于返回布尔结果、启动和停止各种计时器、显示程序的当前状态以及将有趣的内容写入编译器的输出列表的琐碎语句。

Say no.
Say yes.
Set the variable's compiled flag.
Start the compiler's timer.
Stop the compiler's timer.
Show status "Compiling...".
List the globals in the compiler's listing.

119 (约 4%) 在源代码中提前关注焦点,句子如下:

Bump the rider.
Move the rider (code rules).

92 (约 3%) 用于创建、销毁和保持内部索引最新,语句如下:

Create the type index using 7919 for the bucket count.
Index the type given the type's name.
Destroy the type index.

58 个(约 2%)用于在各种列表中查找事物:

Find a variable given the name.

37 个(约 1%)是对各种转换例程的调用:

Convert the rider's token to a ratio.

31(大约 1%)用于生成实际的机器代码(加上那些出现在条件语句中的,如上):

Attach $E8 and the address to the fragment.

这占我们编译器代码的 80%。

剩下的句子中只有 57 个(不到整个句子的 2%)本质上是数学的,像这样到处都有一行:

Add 4 to the routine's parameter size.
Subtract the length from the local's offset.
Multiply the type's scale by the base type's scale.
Calculate the length of the field's type.
Round the address up to the nearest multiple of 4096.

其余的根本不是公式化的。像这样的东西:

Copy the field into another field.
Append the fragment to the current routine's fragments.
Abort with "I was hoping for a definition but all I found was '" then the token.
Initialize the compiler.
Remove any trailing backslashes from the path name.
Reduce the monikette's type to a type for utility use.
Eliminate duplicate nicknames from the type's fields.
Prepend "original " to the term's name.
Extend the name with the rider's token.
Unquote the other string.
Read the source file's path into the source file's buffer.
Generate the literal's name.
Extract a file name from the compiler's abort path.
Write the compiler's exe to the compiler's exe path.
Swap the monikettes with the other monikettes.
Skip any leading noise in the substring.
Scrub the utility index.
Fill the compiler's exe with the null byte given the compiler's exe size.
Position the rider's token on the rider's source.
Pluralize the type's plural name.
Link.
Finalize the compiler.
Check for invalid optional info on the type.

这就是为什么我们说,大多数大多数节目做的是简单的东西,东西,可以在自然语言方便地表示。反过来,这就是我们喜欢用普通英语编程的原因:我们头脑中的想法被输入为普通英语“伪代码”,并且在此处和那里进行调整后,该伪代码实际上可以编译并运行。并且是自我记录的,可以启动。

另一个反对意见得到回应

您可能认为自然语言对于编程来说太冗长了。但真的有那么糟糕吗?让我们考虑几个例子。在传统的编程语言中,我们可能会使用如下语句绘制一个框:

substring.draw ( box, color, source.text.font, source.text.alignment ) ;

这是10个单词和11个标点符号:总共21个元素。

普通英语相当于:

Draw the substring in the box with the color and the source's text's font and alignment.

其中16个单词和3个标点符号:共19个元素。

诚然,纯英文版本需要更多易于输入的字母字符(由于传统编码器将空格放在不同的位置,因此很难准确说出到底有多少);但对于不必学习(或思考)人工语法而言,这是一个很小的代价。

这是另一个例子:

if ( ! source.colorized ( ) ) color = black ;

其中5个单词和8个标点符号:共13个元素。

与普通英语相比:

If the source is not colorized, put black into the color.

其中11个单词和2个标点符号:共13个元素。

同样,这主要取决于您是喜欢输入单词还是(专门的)标点符号。以及您是否喜欢同时以两种不同的句法和语法形式进行思考。以及您是否希望您的代码自我记录。以及您是否想要对初学者友好的代码。和
您是否想用一种 100 年后仍会普遍使用的语言(如英语)进行编码
现在起。就我个人而言,如果您认为“(!source.colorized())”是一种很好的表达方式,我们认为您可能已经失去了一些人性化的视角!

原型

如果你有兴趣,你可以在这里下载整个shebang:

www.osmosian.com/cal-4700.zip

它是一个小型的 Windows 程序,大小不到 1 兆字节。但它是一个完整的开发环境,包括一个独特的界面、一个简化的文件管理器、一个优雅的文本编辑器、一个方便的十六进制转储器、一个生成本机代码的编译器/链接器,甚至一个所见即所得的页面布局工具(我们过去用来生成文档)。它完全用简单的英语写成。源代码(约 25,000 句)包含在下载中。无需安装;只需解压缩。从“documentation”目录中的“instructions.pdf”开始,在你阅读十页之前,你不会只是在写“Hello, World!”到屏幕上,您将自行重新编译整个内容(在沃尔玛的底层机器上不到三秒钟)。

感谢您的时间和兴趣。


格里·泽帕
Osmosian Order of Plain English Programmers 大内格斯


丹·热帕
Osmosian Order of Plain English Programmers 首席汇编员