——Brainfuck!

  BF语言——够简单了吧?一共只有8条指令……

  但这篇文章不会就此结束,BF也不见得“简单”,请看http://esolangs.org/wiki/BF_instruction_minimalization (我是用chorme浏览器翻译的)。在这一“行业”,还可以再认真一点……(何况还有传说中的“单指令计算机”,我不能闻其详)但是我们得再次哲学起来:我们在干什么?

  什么叫简单的编程语言?或者更“本初”的问题,什么是编程语言?一个引导性的问题:Brainfuck算是汇编还是机器语言?(网上能看到用C实现Brainfuck,莫名喜感)我们知道“复杂指令集”和“精简指令集”,而对于后者,百科给出的指令数目是“小于100条”——但是似乎连大多数编程语言的字符可以都少于100个——我知道你要说什么,Brainfuck的每一个字符都是一条【指令】,但是汇编又如何呢?汇编指令常常是带参数的,可见汇编“远比BF复杂”……——所以,从图灵机模型到8086级别,发生了什么?以及,高级语言是怎么回事?

  我们先不谈“语言”,先谈“操作”。“操作”可算是编程中最底层的东西了。操作是什么?我们可以简单定义:1.数个操作组合仍为操作;2.CPU指令都是操作。但这么一来,BF还比汇编高级了?!因此得出“操作基于某一具体处理器”,或者“操作基于底层操作”。我不知道传统CPU有没有“寄存器+1”这个指令,假设没有,那么传统汇编和BF就是可以互相表示并且没有高低之分的。这也警示我们,高级语言的高级也并非在指令上。

  我暂时使用“处理器接口”这一词汇,并且再添2个:“传统处理器”和“BF处理器”。——等等,我好像忘记了BF的最后2个指令?!——不,(应该)还是可以补偿的,或者(也应该)可以修改这条指令,使之成为常见的条件跳转,只需要增加一个地址参数(我真是天才!)我索性创造一种【类BF语言】好了,而且按惯例无视输入输出——

  • 你需要:一串足够长地址,寄存器A和M;一台处理器,不断执行A对应地址中指令
  • 指令1:后接一个参数x,将地址为x的值放入M,A+=2
  • 指令2:后接一个参数x,将M放入地址为x处,A+=2
  • 指令3:后接一个参数x,将地址为x的值加上M放入M,A+=2
  • 指令4:后接一个参数x,将地址为x的值放入A
  • 指令5:后接一个参数x,如果M为0,将地址为x的值放入A;否则A+=2
  • 指令6:停机

  我意识到一个问题:我好像不会证明图灵完备?!虽说有个懒办法,直接实现并写数个程序即可。更懒的办法是,实现BF。但是用C实现BF以证明C语言是图灵完备的,这未免……?

  另一个问题是,switch让多条指令变成一条,也就是以上6条指令,等价于一条switch(可以再用一个寄存器,也可以指定一个地址)。虽然,有什么意义呢?(CPU即switch,见上一篇文)其实还有一个问题,2个寄存器究竟是多了还是少了?

  刚才又想到另一个问题:能不能说“固定地址跳转”比BF中的“跳转到相应……”更“简单”?所谓的“相应”是高级表述,而地址跳转是低级表述?显然二者等价,但有高低之分;但++和+=x呢?(说起来刚才的“类BF语言”缺少减法或者取反)——且慢,我们在干什么?我说了这么久,但似乎漫无目的(吗?)?

  我承认在一开始我没有单刀直入,我写文章也不会刻意安排。那么——

  • BF语言简单吗?
  • BF和汇编有何关系?
  • 怎样的语言是简单的?什么叫简单?

  第一个问题是不用多想的,辩证否定,就指令数量而言,BF很简单,但能更简单。这也部分回答了第三个问题,当“简单”特指指令数量而言时。对于第二个问题,有必要谈一谈编程语言。编程语言是从结构主义开始的,即(“主要是”)我们服从机器习惯。但现在的高级语言开始讲究机能主义,让机器服从我们的习惯(但大体还是延续传统,并不见人直接从需求开始向下设计?)。按地址跳转是(传统)机器习惯,按匹配跳转是人的习惯。指令默认按序执行是人的习惯,但和机器不矛盾(刚才类BF语言每个指令附带的A+=2,其实可以改成任何固定跳转);加减乘除是人的习惯,加法和取反是逻辑底层,++是逻辑更底层。但是条件转移和重复是贯穿始终的,以列竖式算除法为例,此过程是很标准的循环操作。重复在机器层可以不看做指令,因为跳转就可以做到;但在高级语言层,这一过程还是被封装了起来,甚至跳转被隐藏掉了(万能exec不算)。让人想起了20步还原魔方的典故——“上帝视角”:充满goto的代码“只有上帝看得懂”,但是对于只有数条指令的CPU,它甚至不知道上层封装。无论多精妙的软件,最终是由简单指令组合而成,但用汇编直接写……(我不知道,我听说过Warez……)于是我们回答第三问的第二个角度:简单可以指“偏向人的习惯”,但人和机器也可能在某些方面是一致的。所以显然BF(在此层面)不简单了。现在我们只剩第二个问题了,我们不妨加一问:语言是什么?之前说到操作,操作是什么很明晰了;我们现在说“指令”,请注意“指令”既包括语义,又包括形式。我们不妨给“简单”再加一个维度作为参考:“用于表示的符号数目”。机器语言只有1和0,毫无疑问是最简单的(BF要8个,类BF还需要参数)。但仔细想想会发现这个维度没什么意义:我们把C程序中的字符全用二进制ASCII取代,C还是C。——题外话:我们可谓是在研究编程中的语言学了,但是谢天谢地编程中的句子必须是操作(吗?!)——不过这么一想不对劲:要是关键字可以随意换,那C岂不成python的子集了?(引用若干库)语言差别何在?或许就在于这集合关系——既然有Cpython,那么py能做的C必能做(误,我只能肯定py能做的汇编必能做),那语言的意义是什么?再问个问题:【抽象】的意义何在?毕竟语言的意义只能在于抽象了。语言(在这里)当是脱离符号本身谈论的(【语法糖就是语法本身!!】——我觉得我说了一句经典,呵呵)(在(我的)语言学里,符号也该作为语义谈论)很好,所以编程语言的意义就是向上封装。不管是从结构主义还是从机能主义角度。向上封装有利于结构主义向上,也利于机能主义向下。


(这段意识流给我一个启示:人的思维“以目的为导向”沿语义网走,当走到尽头就开始回溯直到走完可能分支。另外这里的“语义网”和专有名词略有区别)


  所以我想设计一门语言,从机器到人。我懂哲学,但我连汇编都不会,怎么办呢?

(2018-1-7 于地球, 完)