@
svenFeng 我想我基本明白你的意思。不过,LZ 的名义目的一直是“通用”编程语言——所以这里有些微妙的差异——特别是考虑工程可行性的时候。
1.考虑整体工作量上的复杂度,无法指望“容易实现”。
我说的实现,当然,首先是语言自身的实现。所以你说的写(正确的) type checker 更容易这样的局部的着眼点是合理的。
但这和不使用 formal spec 的传统做法相比,这其实也只是在 QA 提升了一小部分(即便相比传统方法的提升是决定性的);而作为代价,还明显地多出来了一部分:写验证代码。
据我所知,Coq/Isabelle 作为语言虽然有越来越往通用的方向上走的姿势,仍然还是 proof assistant 为中心,不适合直接实现 QA 以外的部分。
(题外话,其实就是 ML 系的语言都有很浓的 DSL 的味道—— pure functional 在某种意义上是注定无法“通用”到哪去的——就像汇编一样。)
所以,维护这样的语言及实现,得至少找到会同时使用非验证语言(实现语言)和验证语言的部分。
除了 IC 验证等极少数领域,这在工程上整体工作量很可能更多,几乎没有换来周知的正面效果。
2.Formal spec 的一个显著作用和预期目的是使 spec 的精确性更容易保持,尽量减小实现的偏差,而提升整个实现环境的质量。
但很遗憾,这个目的除了极端封闭的个别关键嵌入式产品(……比如月球车)外,因为依赖外部系统的关系,基本没法系统性地实现。
因为 formal spec 使用的 formal semantic methods 到目前为止能做到的最符合这个目的的做法,说白了也只是从一个 abstract model 翻译到另一个而已。
假设 formal spec 作为 source model 的描述是无 bug 的,也不能保证实现无 bug。
所以如果 target model 的实现本身不靠谱,翻译之前的 model 再保证没 bug 也挽救不了整个系统的实现质量(只能排 bug 时更容易踢皮球而已)。
举个例子,你如果用 C++当实现语言,整个系统的实现就别指望严格地靠谱了,因为 C++的 normative spec 不是 formal 的,更没有 C++实现宣称 formally verified。
使用公开的资源,你可能只能选择 C99 的一个子集然后使用 CompCert 来实现才能基本达到这种保守的目的——如果有 bug,bug 基本就是宿主环境和处理器厂商的。
然而考虑到 C 对 strict conforming program 的限制,这对实现整个的语言这种任务来讲,基本没啥意义。
3.上面还是理想情况。更直接的实际困难是,你没法指望保证写对 formal spec ……使之符合 informal 的 endorse 用的吹给用户听的设计的意图(至少对设计一个通用语言讲这是必要的,因为你没法指望它的用户具有足够 formal 脑细胞能自动领会你的设计多提供了传统设计没保证的啥)。
因为得分析确认需求,在你造得出替你思考的强 AI 前,这只能是手动的。我不觉得有谁有能力在“造一个通用语言”的目标上满足这里的人员资源。
此外,“有疑问看 proof ”也只是少数维护者才能做得到的事情。在教用户理解如何使用时,还多出来一遍切换 normative formal 和 informal spec 的工作量,这也是人肉的,也可能出错。
如果这个 formal spec 要 publish,我好像也没看到有谁能直接印 Coq 代码上去就算数了……
其实我觉得如果能印 Coq 代码上去大概还是进步的。我不清楚确切理由(也许是灌水的惯性问题),但是现状是,这方面业界人士似乎都喜欢在明显不适合的地方继续滥用 subsequent calculus 之类的东西。
当然,informal spec 这里也不省心。但是讽刺的是,因为后者不要求那么 formal 到必须通过 verfication,反而是更能“容错”的——不少 spec 的 bug 甚至可以延后解决,而不影响实现的进度。
4.非工程的意义上,如果你想写得整体上让人能看得懂,这样做还有摆脱不了 meta language 不够 formal 的问题——以至于不得不妥协,很难整个 formal 到底。
具体来讲,上面的依赖外部系统换成 spec 本身——项目会有外部 spec 依赖。
比如你能拿 Coq 代码当 formal spec,那么你如何判断 Coq 代码作为工具来说是保证能正确表达你的意思的?是不是还要引用 Coq 的 reference ?或者更极端点,直接把用到的部分包含进来?
然而上面说了,Coq 本身仍然相当地 DSL。在通用语言的 spec 里包含 DSL 的 spec,即便这部分只作为 meta language,我觉得仍然是十足的迷惑行为。
(虽然 Robin Milner 等看起来不那么想,实际上还把 ML 剁成一坨坨分开讲,似乎还很能彰显 ML=metalanguage 的样子——但是他们自己在 spec 用的 denotational 的东西和英语显然很不够 ML ……)
5.暂时忘掉上面所有的麻烦,还有个扩展的问题:spec 如何被用户复用以得到一个派生的语言?
如果 spec 的形式是 proof 堆出来的,那么要么这个派生的语言是 spec 规定的严格的保守扩展,要么就得几乎一个个重新(人肉)检视所有 proof 是否仍然能够符合新的需要。
一类具体的实例是本体论扩展问题。通常意义的 formal spec 中,基本只能使用 closed world assumption (除非你开洞允许用户覆盖 type system 相关的 rule,但都这样了,写死在 spec 里还有啥意义……),而真正意义上的通用语言要求 open world assumption。
你如何设计你的 type 以允许扩展加入新的 disjointed type universe 且确保原有的 typing/typechecking rule 仍能 consistent 且有意义?
当然,可以限制被扩展的语言只能作为 meta language 来彻底回避这个问题,但这又让通用打折扣了。