在程序员的日常工作中,我们实际上同时生活在两个截然不同的语言世界:一个是冰冷精确的形式语言世界,另一个是温暖模糊的自然语言世界。理解这两个语言世界的本质差异与微妙联系,是每个优秀程序员必须掌握的基础能力。
一、缘起
在技术面试中,我喜欢用下面这道题来考察候选人的专业基础深度。从实际反馈来看,它能很好地筛掉那种半路转行,基础薄弱、习惯于堆砌低质量代码的平庸程序员。
什么是形式语言?和自然语言有什么区别?编程语言是形式语言吗?你学过哪些编程语言?计算机是怎么识别并运行编程语言的?计算机是怎么识别并理解自然语言的?
能答好这道题,说明真正理解了“机器思维”与“人类思维”的差异。编程语言是形式语言,人类交流使用自然语言。真正优秀的程序员,要能在这两种思维中自如切换:既能写高性能代码,又能写高质量文档。
二、为什么不能用自然语言编程?
网上关于『能否用汉语编程』的讨论屡见不鲜。这在专业程序员眼中很可笑。其根源在于,提问者看到代码中充斥着if、else、class等英文单词,便想当然地认为在用“英语”编程。这是一种表象认知。所有编程语言,无论其词汇来源何种自然语言,本质上都是一套精确定义、逻辑严密的形式语言体系。它们与自然语言有着本质区别。
那为什么不能用自然语言编程呢?因为自然语言有以下几个特点:
- 充满歧义:同一语句在不同语境下有不同含义
-
我喜欢吃香蕉" # 是喜欢"吃"这个动作,还是喜欢"香蕉"这个食物?
-
"他谁都不认识" # 是他不认识任何人,还是任何人都不认识他?
- 语境依赖:理解需要背景知识和上下文
- "那个东西放在老地方" # 什么是"那个东西"?哪里是"老地方"?
- 灵活多变:允许语法错误、省略、创新表达
-
"你吃了吗?" ≠ 真正询问吃饭情况,而是问候语
-
"蓝瘦香菇" = "难受想哭"的创新表达
- 冗余性强:包含大量重复、修饰信息
- "我亲眼目睹了那个令人震惊的、难以置信的场面"
虽然现在AI可以理解自然语言并生成代码,但对计算机而言,最终运行的还是用形式语言编写的代码。
三、形式语言
在数学和计算机科学中, 形式语言(Formal language)是指用精确的数学或机器可处理的公式定义的语言。与自然语言相比,形式语言最大的特点是它是通过严格数学规则定义,精确无歧义的(计算机不会犯错的底层原因)。相关知识可阅读编译原理等专业书籍,这里不深入讨论。
和自然语言相比,形式语言有以下特征:
-
精确无歧义:每个符号都有唯一确定的含义
-
结构严谨:语法规则严格,违反即导致错误
-
逻辑驱动:基于数理逻辑,强调因果关系和确定性
-
人为设计:由个人或团队创造,有明确的规范和版本
正是因为形式语言是由精确的数学规则定义,使得我们能够设计出对应的抽象计算模型——自动机——来识别和处理它。根据乔姆斯基谱系,形式语言及对应自动机可分为以下四类。
所有的编程语言都是形式语言,且大部分主流编程语言(如C,Java,Python、JavaScript等)的语法规范都使用类似BNF(巴科斯-诺尔范式)的形式,这属于2型文法。****
四、桥梁:自然语言处理(NLP)
理论上,确定性的形式语言是无法“理解“非确定性的自然语言。自然语言理解中那些可以被精确定义的部分(如特定文法下的解析、逻辑形式转换、特定形式的推理),很多都被证明是NP难的,甚至更难。就算是0型形式语言,即图灵机,也无法在多项式时间内解决NP难问题(扩展阅读:《可计算问题的边界》)。
那么现代计算机是如何做自然语言处理的呢?答案是引入了数据来解决不确定性。更准确地说,我们借助形式语言(及其扩展,如概率模型和神经网络)作为工具,来构建能够处理和模拟自然语言理解的系统。今天的“理解”成果,是大数据、强大算力和这些精巧形式模型结合的产物。形式语言提供了最初的蓝图和骨架,而现代机器学习则用数据为这副骨架填充了血肉,使其看起来拥有了“理解”的能力。
五、编程实践中的启示
程序员的双语生活:翻译的艺术。程序员的工作本质上是在这两种语言之间进行翻译:
-
需求分析阶段:将利益相关者模糊的自然语言需求(“我们需要一个用户友好的界面”)转化为精确的技术规格
-
编码阶段:将算法和逻辑转化为形式语言表达,同时用注释(自然语言)解释“为什么”这样实现
-
文档编写:用自然语言解释形式语言构建的系统,为其他人类开发者提供上下文
-
调试过程:在机器报错(形式语言)和实际问题(自然语言描述)之间建立联系
两种语言的交汇点:注释、文档与命名。优秀程序员在这两种语言的交界处尤其出色:
-
有意义的命名:变量名userAge比ua更好,因为它在形式语言中嵌入了自然语言的含义
-
注释的艺术:好的注释解释“为什么这么做”,而不是重复代码“做了什么”
-
文档的平衡:技术文档需要结合形式语言的精确(API参数类型)和自然语言的解释(使用场景示例)
六、总结
形式语言是与机器对话的基石,它要求逻辑严密、毫无歧义,这直接塑造了我们严谨的抽象与架构能力。而自然语言的模糊性与丰富语境,则映射着多变的需求与用户体验。真正优秀的程序员,能在这两种思维中自如切换:既能用形式语言的精确实现复杂逻辑,构建系统的坚实骨架;又能用自然语言的共情理解模糊需求,为其注入顺畅交互的血脉。 二者兼修,方能既打造出坚固可靠的工程,也创造出真正为人所用的产品。