Skip to content

Instantly share code, notes, and snippets.

@FrankHB
Last active July 31, 2022 13:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save FrankHB/93304e6fd8db29e6368e32a1922205c7 to your computer and use it in GitHub Desktop.
Save FrankHB/93304e6fd8db29e6368e32a1922205c7 to your computer and use it in GitHub Desktop.

Re 0

@Suddoo 你还真是 you can you up 惯了啊,是会自己做 λvC calculi(哦,你 Java 还不大配,没提供 continuations )的作业的程度所以自信爆棚了么?

不好意思,我都无中生有重新发明过 lexical-scoped FEXPR,还真看不上 lambda 当 primitive 的语言,更别说什么还要搞 object calculi 的煋闻的,特别还还要特设语法,居然默认还没 first-class function ……算了,给你科普太麻烦,省略鄙视链到 Java 的中间环节若干。 没点专业常识就闭嘴,OK ?

当然鄙视你不如鄙视 Gosling ,至少鄙视一些偏执设计思路(比如消灭多继承却无视 mixin 的需求)对大众有一些破除迷信伪劣权威的教宜,你就算被充分鄙视了又算老几能有啥影响?但是中间仍然有若干鄙视链差距,比如说也不如鄙视好歹还会承认 feel educated 的 GvR

挂婊这种程度的设计居然还需要打工?你打的什么黑工?

@iosyyy 我没说不能写啊……但写了这质量么,平均下来大约就是足以怀疑这种选型是跟用户过不去。

Electron 除了 vscode 有几个有点规模的项目能看的?有几个项目能有 vscode 财大气粗坑资源不眨眼?投入产出成比例?

而且 vscode 这么极端的优化在满足性能需求上也就是“能用”而已。其它优点就没一个是 GC 提供的,GC 的吞吐量之类的优势在客户端领域中发挥不出来,就光拖后腿了,还误导思路,破事一堆,还搞得一些从业人员水准低下理解不了基本业务需求

关于 Electron 这方面的鄙视也不是我发明的,怕是 v2 常识了,我回复过的都有几页。你要不信可以开主题问。而我这里不过顺便把地图炮泛化了—— Electron 有的问题,在基于所谓的 GC 语言的方案中或多或少都有,并且流毒甚广后果严重,仍不可掉以轻心。上面从业人员素质的问题就是一个例证。

我的鄙视都有明确的技术理由,而这跟流行程度无关。这里列举的东西故意都是非常形而上的有全局影响的东西,以避免某些人一根筋不清楚问题的严重性。共同点是一些决策的机 会成本和沉没成本应用到工业语言都不是个别社区能够承受的,搞不定设计者弃疗是很容易现实——但先不说我的立场如何——难道没本事影响语言设计决策的普通用户就活该接受残废吗?

少恶心人了。

没有同像性导致反射的特性是名义而不是自动结构化的:现实需要人工遍历(甚至就算有形式语义也没救)现有特性做选型以便确定具体打算支持反射哪些东西,现在C++(都缩水到编译时了)就很大程度就卡在这种二货问题上了。如果一开始就不允许一些残废的设计,根本就没有这种破事(虽然这样可能一开始就没C++了……)。

欠缺 lambda 残废就更容易理解了——你从 lambda 扩充出 closure 实现什么 class 之类的东西成本比现在所谓的 OO 语言低多了。说白了 lambda 就跟其它大多数特性就不是同一层次的东西,要远远基础得多,所以没搞清先来后到制造残废理固宜然。

现状么,就是大多数用户光顾着吔现有垃圾语言设计的翔,没能力二次开发,没余裕发表不满,甚至经验可怜到连放地图炮的武德都没有。我做得到能放地图炮而且不误伤,自然就要出头,否则真当有点追求的用户都一起是傻子活该吔翔咯?当然我没强迫这些可怜人出头,所以我说了,我骂的不见得对这些人有意义——就没能力理解。但没眼力见到连闭嘴都不会,那就是先于浪费资源的历史包袱本身欠骂了。光是嘴炮荡平这些不开窍的用户,就比解决现有语言的垃圾设计容易不知几个次元。

顺便提醒一下外行图灵机 fanboy :图灵机在 PL 历史上的重要性相比 lambda 演算(LC) 可以忽略,基本就只是因为历史上的 Church-Turing thesis 才有存在感,换了 Post 机之类的备胎也能达到目的;Kleene 算术层级之类的扩展原则上不需要图灵机;而 LC 则是另一侧的一切非超图灵机的机器下可实现的高级语言的原型——基本上你发明了任何一种足够“高级”(具体点,有变量和函数)的语言,就能把操作语义规约到 LC 的某个保守扩展(typed LC 也同时是类型系统的基本模型),所以反过来扩展 LC 可以量产所有现实可用高级语言的模型(比如说 λvC-calculus 算是 Scheme 中的一个典型子集),甚至 unlambda 这种背靠组合子逻辑的故意不高级语言的代表还要从 LC 做减法才能实用地写出被人理解的程序。可以说在可行性的问题上已经被 LC 这一套方法做完了,就算有其它方法也是改进具体特性的选型效率,或者大多数语言一样先瞎设计之后严格化语义发现是 LC 的一个扩展。而图灵机算哪根葱,除了“图灵完备”这个词以外有什么特殊性来碰瓷?

所以所谓“大家都是图灵机”,说白了就是对所有 PL 的侮辱——认为计算能力(可表达性)一致,抽象能力就无关紧要。那说实话高级语言这种东西不就是多余的,要啥区别?这几十年都在折腾啥,直接一种语言不更省事?

Re 1

城门

Suddoo

@FrankHB 你真的废话好多

还喜欢搞一堆文言文和洋文虚张声势、就是拿不出啥实质性的东西出来……

哦,看不懂 = 废话 = 虚张声势。行吧,算是承认不值得让人浪费铜币回复了?

那就直接挂着吧。

复制自评论区

我觉得评论区的一部分内容对一般读者有意义,所以就复制过来了。

@iosyyy 我不得不指出你的理解不着边际,还有不少直球跟实际事实相反的内容。“大家都是图灵机”说的就是都图灵完备,跟拿来编程几乎毫无关系。实际能拿来编程的系统的图灵等价的证明几乎全是后设的。甚至高级语言证明图灵完备的靠谱的标准流程就是先规约到 λ 演算的一个扩展,然后通过 lambda 演算的图灵完备性做推论。也就个别低级语言可以不用,比如 Brainfuck 这样的语言就是为了和图灵机原生地贴贴而发明出来的,没有变量也没有函数,而直接改自动机状态来描述语义——这才是属于你所谓的“模拟图灵机的过程”的实例。而自称函数式编程的语言,没有一种这么做,至少我不知道现在有自称函数式还不支持变量的高级语言的存在。低级语言方面,组合子逻辑作为语言不支持变量,但它充其量是 FLP(function-level programming) ,而不配是最宽泛意义上的“函数式”语言,因为其中的“函数”(组合子)无法作为一等对象;事实上,一等对象要求对象能被变量引用,说白了下限就已经是高级语言。

注意,我说过这适合所有高级语言,具体来说就是有变量和函数的语言,这些语言在基本结构上高度类似。甚至相似的结构视角还可以涵盖其它一些比 λ 演算更低级的语言(如组合子逻辑)——它们都很方便用项重写系统描述操作语义,而 λ 演算是历史上第一个正经研究的项重写系统。(这也是我反复强调 λ 演算作为模型在 PL 中远远超过其它备胎模型的主要原因。)这些事实和具体语言发明人和用户的意思都基本无关,比如 Scheme 自称“过程式”却时常被当作“函数式”,是这种模型“正统”扩展(λvC)的一个直接实例,而 C 语言这种表面上一点都不“函数式”的语言同样是这种扩展的实例(即便 DMR 压根就没这方面研究),只不过除了类型系统以外抽象能力明显更弱(不支持一等函数、不支持续延)。这反而倒是解释了 Scheme 自称“过程式”的合理性——过程说白了就是一类具体的“函数”,或者说 λ 演算中的 λ-抽象这种语法的具体扩展的统称(主要扩展在这些语言不像 λ 演算的语义支持任何 λ 项作为“函数”,实际上要求多出来对操作符项的类型检查)。任何人发明什么新的高级语言,都逃不出这种窠臼——不论有人想如何无视,这就是群魔乱舞的所谓理论计算机科学最后所剩无几的、还能勉强称得上是“科学”的现实理由了。(虽然其实这里没法让自然科学和数学划清界限。)

现在的高级语言在计算机上的实现也没利用计算机作为通用图灵机的常规思路。像 C 语言经过翻译编码出来的机器码制造调用栈之类的活动记录的源语言中不可见的管理(administrative) 操作,其实能视为一种比通常的演算式的操作语义更底层的另一种风格(抽象机)的小步语义的实现中的必要步骤。虽然从抽象机的配置来看似乎像是图灵机这样的自动机模型,但描述这些实现的元语言是类似 λ 演算的传统演绎系统的语言,而不是自动机这样的状态转移,根本上是不同的东西。这在讨论具体实现更显得必要,因为前者可以限制具体的组件和配置数(对应具体机器的架构寄存器集合)而视为某种“寄存器机”,而不像图灵机上来就是一坨纸带(基本上只能对应主存,还需要多“编译”写出配置,差不多就是你想象怎么把高级语言编译成 Brainfuck 那样奇葩的中间表示),所以现在研究体系结构对语言实现的支持时,图灵机也是多余的。顺便,实务意义上,栈机也应被以类似的理由嫌弃,即便作为虚拟机它没像图灵机要求那么重量级的“编译”——那也只是因为最简单的函数调用以栈实现最简单罢了,但 LIFO 根本就不是函数调用的全部内涵;甚至光是 λ-抽象的应用(“函数调用”)的替代实现——不用 λ 演算的 β-规约中的替换重写规则,而是像 Lisp 这样依赖环境——就不那么容易对应到栈机上去。实际上,在物理机器上编码类似实现调用的数据结构的这个需求直接促使了 P. Landing 在 1964 年提出第一代语义抽象机—— SECD 机。虽然这个机器现在看不那么有意义被实现,但里面有个划时代的发明——词法闭包,光是这点,就值得一般语言的专业用户作为常识理解(或者死记硬背)。另外,这个视角也解释了为什么栈机要么只能堪堪满足实现比较弱鸡的“传统”语言(嗯,比如 Java )的要求,要么干脆污染到对象语言(比如 Forth )的特性上;而其它语言非得用栈机实现就比较别扭和低效。

我特意提前给图灵机 fanboy(我不是针对你,但本质上这样的就是道听途说的小鬼)加了一段技术背景的解释,就是预防这种在根本方向上的理解错误。任何基础不牢靠的同学都应该引以为戒。

算法+数据结构=编程是另一个流行的误解,本来也就是 Wirth 糊弄外行人用的。然而 Wirth 在 ALGOL-like 语言以外的领域的成就相当有限(连图灵都远不如),真信这种教条你就上当了。

事实是,算法和数据结构都是依赖具体形式模型(元语言)表达的抽象结构(代码)。其中,数据结构说白了就是一种元语言下放通过演绎规则允许表达的功能模块,而相比笼统的算法更没有什么独立性(所以最近几十年有搞传统通用算法的,却几乎就没什么正经研究所谓数据结构的,因为融合到语言的计算模型中了)。而笼统的算法也经常缺少讨论的意义——因为严格意义上,不选择形式模型就没法精确无歧义地确定你讨论的算法是什么东西。如 TAOCP 给算法的多元组定义其实就是给了一个极其简陋的最小抽象,勉强说明“算法”和“非算法”的边界,但是对研究算法来说通常还是不够的。因为,元语言作为计算模型,其选择会极大影响算法自身能表达的内容,以至于大多数非平凡情形无法忽略。极端情形元语言的表达能力有上限,还会影响可表达性——就像量子图灵机作为计算模型不能直接映射到图灵机一样。但是更多情形,所有现实模型都是图灵完备的,所以要讨论区别就不会计较不同模型之间的表达能力的不同。

重点是:即便你正确理解了表达能力的不同的来源,也不表示你能轻易地忽略表达能力以外的不同——大量的可读性、可维护性、代码构造复杂性的度量全是依赖这些具体不同的性质,而图灵完备相比是一个司空见惯到很次要而不值得关注的前提,除了一种情况:有时你还要依赖图灵完备来提升可用性:比如类型检查就不能无条件地图灵完备,要知道图灵完备是可以允许死循环的,这样静态类型检查就直接没法用了。实际上试图尽量滥用图灵完备而模拟类型检查的实现的体验极其捉急,比如想像 C++ 模板元编程撞上模板展开极限前会输出些什么错误。

忽略计算模型的选择而笼统讨论这些性质已经有了极大的假设,这充其量只是偷懒;而 Wirth 能说的出口也是因为他会教人使用的模型(编程语言)都有高度的相似性。换一个对各种范型都认识的作者或者干脆就是传统的数理逻辑学家来描述算法和编程的关系,怕是没敢夸这种海口的。而干掉这种误导虽然也不算简单,起码是比干掉谭×这样的胡说八道从头误导到尾的语言教材造成的思维定势的性价比是高得多的,所以在正经的场合中,我一直优先排除这种大毒草口嗨式的教条。

@iosyyy
Copy link

iosyyy commented Jul 31, 2022

"大家都是图灵机"说的是现在的语言都在用另一种特性模拟图灵机编程 这几十年大家干的都是这样的活 因为现代计算机本质上就是图灵机 因为图灵机简单 我没有说抽象能力无关紧要可事实如此 算法+数据结构=编程和当年用纸带的图灵本质上没区别

@iosyyy
Copy link

iosyyy commented Jul 31, 2022

像现在的函数式编程很多都是模拟图灵机的过程

当然这是我浅薄的理解 我认为其他特性不是没必要像你一直在说的lambda 但是本质上目前为止在pc上都是做的模拟图灵机的活没有为啥因为他简单..... 说实话lambda出现比图灵机还早上不少..

@FrankHB
Copy link
Author

FrankHB commented Jul 31, 2022

@iosyyy 我不得不指出你的理解不着边际,还有不少直球跟实际事实相反的内容。“大家都是图灵机”说的就是都图灵完备,跟拿来编程几乎毫无关系。实际能拿来编程的系统的图灵等价的证明几乎全是后设的。甚至高级语言证明图灵完备的靠谱的标准流程就是先规约到 λ 演算的一个扩展,然后通过 lambda 演算的图灵完备性做推论。也就个别低级语言可以不用,比如 Brainfuck 这样的语言就是为了和图灵机原生地贴贴而发明出来的,没有变量也没有函数,而直接改自动机状态来描述语义——这才是属于你所谓的“模拟图灵机的过程”的实例。而自称函数式编程的语言,没有一种这么做,至少我不知道现在有自称函数式还不支持变量的高级语言的存在。低级语言方面,组合子逻辑作为语言不支持变量,但它充其量是 FLP(function-level programming) ,而不配是最宽泛意义上的“函数式”语言,因为其中的“函数”(组合子)无法作为一等对象;事实上,一等对象要求对象能被变量引用,说白了下限就已经是高级语言。

注意,我说过这适合所有高级语言,具体来说就是有变量和函数的语言,这些语言在基本结构上高度类似。甚至相似的结构视角还可以涵盖其它一些比 λ 演算更低级的语言(如组合子逻辑)——它们都很方便用项重写系统描述操作语义,而 λ 演算是历史上第一个正经研究的项重写系统。(这也是我反复强调 λ 演算作为模型在 PL 中远远超过其它备胎模型的主要原因。)这些事实和具体语言发明人和用户的意思都基本无关,比如 Scheme 自称“过程式”却时常被当作“函数式”,是这种模型“正统”扩展(λvC)的一个直接实例,而 C 语言这种表面上一点都不“函数式”的语言同样是这种扩展的实例(即便 DMR 压根就没这方面研究),只不过除了类型系统以外抽象能力明显更弱(不支持一等函数、不支持续延)。这反而倒是解释了 Scheme 自称“过程式”的合理性——过程说白了就是一类具体的“函数”,或者说 λ 演算中的 λ-抽象这种语法的具体扩展的统称(主要扩展在这些语言不像 λ 演算的语义支持任何 λ 项作为“函数”,实际上要求多出来对操作符项的类型检查)。任何人发明什么新的高级语言,都逃不出这种窠臼——不论有人想如何无视,这就是群魔乱舞的所谓理论计算机科学最后所剩无几的、还能勉强称得上是“科学”的现实理由了。(虽然其实这里没法让自然科学和数学划清界限。)

现在的高级语言在计算机上的实现也没利用计算机作为通用图灵机的常规思路。像 C 语言经过翻译编码出来的机器码制造调用栈之类的活动记录的源语言中不可见的管理(administrative) 操作,其实能视为一种比通常的演算式的操作语义更底层的另一种风格(抽象机)的小步语义的实现中的必要步骤。虽然从抽象机的配置来看似乎像是图灵机这样的自动机模型,但描述这些实现的元语言是类似 λ 演算的传统演绎系统的语言,而不是自动机这样的状态转移,根本上是不同的东西。这在讨论具体实现更显得必要,因为前者可以限制具体的组件和配置数(对应具体机器的架构寄存器集合)而视为某种“寄存器机”,而不像图灵机上来就是一坨纸带(基本上只能对应主存,还需要多“编译”写出配置,差不多就是你想象怎么把高级语言编译成 Brainfuck 那样奇葩的中间表示),所以现在研究体系结构对语言实现的支持时,图灵机也是多余的。顺便,实务意义上,栈机也应被以类似的理由嫌弃,即便作为虚拟机它没像图灵机要求那么重量级的“编译”——那也只是因为最简单的函数调用以栈实现最简单罢了,但 LIFO 根本就不是函数调用的全部内涵;甚至光是 λ-抽象的应用(“函数调用”)的替代实现——不用 λ 演算的 β-规约中的替换重写规则,而是像 Lisp 这样依赖环境——就不那么容易对应到栈机上去。实际上,在物理机器上编码类似实现调用的数据结构的这个需求直接促使了 P. Landing 在 1964 年提出第一代语义抽象机—— SECD 机。虽然这个机器现在看不那么有意义被实现,但里面有个划时代的发明——词法闭包,光是这点,就值得一般语言的专业用户作为常识理解(或者死记硬背)。另外,这个视角也解释了为什么栈机要么只能堪堪满足实现比较弱鸡的“传统”语言(嗯,比如 Java )的要求,要么干脆污染到对象语言(比如 Forth )的特性上;而其它语言非得用栈机实现就比较别扭和低效。

我特意提前给图灵机 fanboy(我不是针对你,但本质上这样的就是道听途说的小鬼)加了一段技术背景的解释,就是预防这种在根本方向上的理解错误。任何基础不牢靠的同学都应该引以为戒。

算法+数据结构=编程是另一个流行的误解,本来也就是 Wirth 糊弄外行人用的。然而 Wirth 在 ALGOL-like 语言以外的领域的成就相当有限(连图灵都远不如),真信这种教条你就上当了。

事实是,算法和数据结构都是依赖具体形式模型(元语言)表达的抽象结构(代码)。其中,数据结构说白了就是一种元语言下放通过演绎规则允许表达的功能模块,而相比笼统的算法更没有什么独立性(所以最近几十年有搞传统通用算法的,却几乎就没什么正经研究所谓数据结构的,因为融合到语言的计算模型中了)。而笼统的算法也经常缺少讨论的意义——因为严格意义上,不选择形式模型就没法精确无歧义地确定你讨论的算法是什么东西。如 TAOCP 给算法的多元组定义其实就是给了一个极其简陋的最小抽象,勉强说明“算法”和“非算法”的边界,但是对研究算法来说通常还是不够的。因为,元语言作为计算模型,其选择会极大影响算法自身能表达的内容,以至于大多数非平凡情形无法忽略。极端情形元语言的表达能力有上限,还会影响可表达性——就像量子图灵机作为计算模型不能直接映射到图灵机一样。但是更多情形,所有现实模型都是图灵完备的,所以要讨论区别就不会计较不同模型之间的表达能力的不同。

重点是:即便你正确理解了表达能力的不同的来源,也不表示你能轻易地忽略表达能力以外的不同——大量的可读性、可维护性、代码构造复杂性的度量全是依赖这些具体不同的性质,而图灵完备相比是一个司空见惯到很次要而不值得关注的前提,除了一种情况:有时你还要依赖图灵完备来提升可用性:比如类型检查就不能无条件地图灵完备,要知道图灵完备是可以允许死循环的,这样静态类型检查就直接没法用了。实际上试图尽量滥用图灵完备而模拟类型检查的实现的体验极其捉急,比如想像 C++ 模板元编程撞上模板展开极限前会输出些什么错误。

忽略计算模型的选择而笼统讨论这些性质已经有了极大的假设,这充其量只是偷懒;而 Wirth 能说的出口也是因为他会教人使用的模型(编程语言)都有高度的相似性。换一个对各种范型都认识的作者或者干脆就是传统的数理逻辑学家来描述算法和编程的关系,怕是没敢夸这种海口的。而干掉这种误导虽然也不算简单,起码是比干掉谭×这样的胡说八道从头误导到尾的语言教材造成的思维定势的性价比是高得多的,所以在正经的场合中,我一直优先排除这种大毒草口嗨式的教条。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment