本文关键字:为语言学习划分一个核心工程。双核语言
说到最常见的编程语言,肯定是c,不光因为它是专业非专业的学编程人士首先接确到的第一门教程级语言,也是因为所有语言都是某种“c系派生”,,,可是它足够简单吗?如果把它放在跟现在的那些语言在一起,它肯定是最简单的(一门语言最重要的就是它支持并内建的简元类型和数据结构,运算符,流程语句,作用域,抽象类型/用户类型支持。其它的都是库级和应用级的。,,而c语言规则和标准库都可以在几小时看完并理解,内置的数据结构只有数组,内置的复合数据类型只有结构体/同位体/位域,唯一的高阶语法是指针和函数数组结合处的应用,排除c面向的问题域全是内存池,编译原理,数据库引擎实现不讲,c本身的语言级复杂性就仅来自在这,在于基于指针可以形成很强大多变和复杂的抽象和它一些其它部分的二义性,),换句话说,c建立了现代高级语言学习和应用的标准核心和最低入阶曲线标准。过程式足够图灵完备学好它已经足够启动编程学习,其它语言只是在c的核心上扩展出其它的机制并集成到自己的核心层,造就出的新的学习曲线,选择性学习即可。
但是考察现在新出现的编程语言,如果向大部分和绝大多数非专业的人打听学习它们的复杂度,十之八九得到的答案会是:c本来就很难了,新的编程和编程语言也越来越难了------ 这不光是因为当代编程始终停留在“c风格,用专业的手段干专业的事情”上,从几十年前的C时代开始也没什么本质面向降低难度的变化(见《一种云化busybox demolets的设想和一种根本降低编程实践难度的设想:免部署无语法编程》)而且还是因为,新出现语言的过程中对往往着重于对c增强cpp进行简化的工作,现代语言的核心往往反而在C过程上集成了越来越多复杂的东西,成为新的复杂度标配,但殊不知对c的简化或许更为必要。因为它决定一个最小学习核心。(见《一种最小(限制规模)语言kernel配合极简(无语法)扩展系统的开发》中的解决方案)----- 这一切都阻碍了很多人想学习编程和坚持下来的决心。
多语言学习为什么要强调一个极简语言核心和标准,和如何去做
因为从不专业到专业,一个人要学习的逻辑体量当然是从少到多,比如对于一个普通人,一般来说,一个类型系统,词法和语法,函数,运算符这些过程式对他们来说就足够复杂了,不能再多了,以后面临多语言学习的需求下,最好是所有的语言共享一个基本相同的类C基础和核心。
除此之外,逻辑的内部体量也应该小,人的属性和学习过程只能是举一反三,前后相续,逻辑不用断层,这样容易建立联系,否则会给学习曲线造成不小的断层无法继续。我们应该用已有的抽象去建立抽象,而不是不断提出新的抽象。用已有的道理去解释新道理。
lua/js/python的核心复杂度比较
最小的应用开发语言核心应该只提供什么?我们用相关的lua/js/py来分析其复杂性。
首先,c的过程式肯定是一门现代语言必须集成的。
1)事情要从最近的语言都加入了函数式(不要把这里的函数式想象成过程中的函数)开始。函数式在80,90年代非常流行,现在热度也不减,它本来是数学上专业的东西,冯氏机or函数机曾经也是选型圣战之一。它的典型特点和给类c语言新增的复杂度,就是提出了函数也是值,也能进入表达式和变量,那么为什么过程式能干所有的事,足够图灵完备,还要函数式呢,因为函数式有巨大的好处,是升级了的过程,1,函数能保存状态和携带数据(过程中的函数只是数据处理器,只能在参数等出入口放置数据),成为某些设计必要的东西和原来过程下的代替如callback,2,函数能给数据结构天然的迭代器抽象促成for each in,3,函数给协程和用户级多任务/异步机制有天然的支持。4,函数能表达高阶数学抽象就不说了。
lua只是有限地利用了函数。而像js这样的语言,起源于c+一种Scheme函数语言,整个编译器实现处,用函数可以作为”元“,解释和实现很多其它的语言机制,比如面向对象,甚至面向过程本身,允许类似直接在抽象树上写程序的方法(即用户用函数写程序实际上模拟了一种语言发明,库级的东西与语言级原理相当对应)。
所以对于深刻理解了函数机制的人,他们很容易学会lua或js的函数部分和非函数部分。对于初级入阶的人,也显得相对学习起来容易。这就是js函数的举一反三机制。
这样看来,拥有c过程和函数为kernels的语言其实也不复杂。比如lua,js,都在接受范围之内,但js干脆把class这种udt/adt和oo(有class不一定要oo)也归入语言核心,实际上就有点过于复杂了。lua和js还有一个历史共同点,都有过成功的jit实现。
2)另外一种极端是py,它也容易举一反三。因为它在数据类型上(它区别于js的地方在于用内置数据结构造扩展而不是提出一种作为代码结构的函数机制),像lua一样,统一为某种meta数据结构,lua是table+metable,py中一切即对象,扩展语言的方法是库级扩展这个宠大的对象系统(其本质是在传统运行期执行栈帧中增加新的数据结构-也是发明py本身的技术,相比之下js的更类似于某种写ast的动作-也是发明js自身的技术),不过py复杂度总体上跟lua和js没法比较,因为python它强调battery included in stdlib,而lua和js只有一个最小核心和最小标准库。
可以看出,py和js都是用语言自身的机制造语言并允许用户扩展语言自身(下面会谈到terralang借助metaprogramming允许你将库真正写成语言而且可import as lib到terralang),而java,cpp这些,用rtti这种完全新提出的东西造class和OO。前者没有增加用户学习曲线的复杂性,而后者增加的不是一大坨。
这样,lua实际上在c的基础上,至少增加了二种高阶语法体系,如果说c只有指针,lua实际上有面向函数和面向对象的气质和血统了(lua的模式匹配用来抢php,perl的市场也是kernel级的?)而过程式+函数式,往往是一种现代语言核心复杂度的标配了。。不过lua不同的地方在于,它聪明地让该属于核心的部分放到核心,把该留给用户的部分还给用户和库,以及应用。
3)lua/luajit聪明的地方还在于,它自己不准备发展得越来越大而定位于与宿主语言(这其中它只全面拥抱c)协作,所以它所有的机制包括扩展都足够“简元”,luajit的ffi使得lua就是c的脚本版本(而且这种互操作非单向而是严密双向的),使得c实际派生出另一个cscript分支,而避免了像js和py这种语言一样将这一切(编程涉及到的二种职责,见《一种最小(限制规模)语言kernel配合极简(无语法)扩展系统的开发》)放到一门新设计的语言kernel中。显式化这二者的界限而不是集成到一起模糊化反而是重要的。
这种可分的结合是非常合理的:c需要lua扩展,因为它解决了“用c实现对象系统”,C不能构建高级抽象的传统难点,而lua也需要c,因为一些扩展只能用系统逻辑实现来写。这二者相互穿插,在他们的领域都互相需要。而且你放心,能saveobj到exe的terra代码也允许是纯pure lua code。lua runtime/c runtime都可以分别发布,terralang只是整合它们形成的一个console editor性质的东西,在terralang中并没有runtime,savetoobj的terra source .t只需lua runtime便可运行,不必带terralang这个近100m的宠物大物。
对于cscript,我们在《qtcling》《terracling》中讲到选型一门真正的c脚本的历程,但似乎只有ffi+lua才是真正的优选之道。
这一切的作用,就是控制了良好的外部复杂度和留给用户入阶处能举一反三的余地。
terralang:一种terra/lua组成的混合的最简应用开发语言核心和扩展体系
再来详细说说terralang,它是代替lua/c(这二种语言本来就是极简的)作为语言standalone kernels复杂度控制的新招:混合kernels。它进一步发展了上述c和lua的关系(相互扩展和混合),更加科学和实用地将复杂度控制和各层用户入阶考虑做到了极致。避免了单kernel的根本缺陷。
怎么说呢?terralang基于clang,是一个极强的静态分析工具,可以让古老的c工作在一个现代的实现平台上(terra),terrlang中的terra是用clang实现的编译型语言,它面向接近c,却力求与lua靠扰,追求terra/lua之间的混合编程(terra中可lua,lua中可terra,顶层是lua,terra只是embeded并被lua metaprogrammed,你可以将terralang视为一个lua,一个lua with terra extends, standalone mixed terra/lua:terralang )。继续了独立的lua/c/ffi时代这二种语言间的交互能力工作。将这一切发展到一门”双核语言“上,方法是:terra函数是一种lua value,就像函数是一种lua type/value一样,然后统一terra/lua上下文语境中的词法作用域。这样二门语言就混合了
(此处不设回复,扫码到微信参与留言,或直接点击到原文)