用编程视角理解英语语法

一、数学里的函数:自变量决定了"求值"需要几个输入

在数学里,一个函数被定义出来的第一件事,就是规定它需要几个自变量:

f(x) = x²                  // 一元函数,需要 1 个输入
g(x, y) = x + y             // 二元函数,需要 2 个输入
h(x, y, z) = x·y + z        // 三元函数,需要 3 个输入

函数本身只是一个"规则",规则要落地成一个具体的值,必须把所有自变量都填满。少填一个,这个表达式就无法求值,只能停留在"未完成"的状态:

g(3)        // 缺少 y,无法求值
g(3, 5) = 8  // 参数齐全,求值成功

这里的关键概念是:函数的定义本身自带一份"需要几个输入"的规格,这份规格是函数与生俱来的属性,不是使用者临时决定的。你不能任意决定给 g 传一个参数还是三个参数——函数签名早已锁死了这件事。

二、编程里的函数:签名(Signature)与实参(Argument)

编程语言把这套数学逻辑原封不动地继承了下来,还给它们起了更精确的名字。以 TypeScript 为例:

function add(x: number, y: number): number {
  return x + y;
}
  • add 这个函数的签名(signature)规定了它必须接收两个 number 类型的参数。
  • 调用函数时实际传入的值,比如 add(3, 5) 里的 35,叫实参(argument)
  • 如果调用时少传参数:
add(3);   // TypeScript 编译报错:Expected 2 arguments, but got 1.

程序在编译阶段就会因为"参数数量不满足签名要求"而报错——这跟数学里 g(3) 无法求值,是同一件事的两种表达方式。

值得注意的是,"argument"这个英语单词,从数学到编程,含义几乎没有变化:都是指为了让某个规则/函数完整运作,而必须提供的输入。这个词后来被语言学直接借用,正是下一节的主角。

三、泰尼埃:动词也是一种函数

20 世纪 50 年代,法国语言学家吕西安·泰尼埃(Lucien Tesnière)观察到一个现象:动词跟数学函数极其相似——每个动词天生就规定了它需要几个"参与者"才能构成一个语义完整的事件。他借用化学"化合价"的说法,把这个属性命名为配价(valency)

用编程语言的方式重新表述泰尼埃的洞察,几乎不需要做任何翻译工作:

function sleep(subject: Entity): Event              // 一价函数
function read(subject: Entity, object: Entity): Event  // 二价函数
function give(subject: Entity, recipient: Entity,      // 三价函数
              object: Entity): Event

give 这个"动词函数"的签名规定了它需要三个输入才能求值,也就是构成一个完整的"给予事件":

give("She", ???, ???)                    // 参数不足,事件未完成
give("She", "him", "a book")             // 参数齐全,事件成立

对应到英语句子:

*She gave.                    // ✗ 参数不足,不合语法
She gave him a book.          // ✓ 参数齐全

*She gave. 之所以不合语法,跟 add(3) 在 TypeScript 里编译报错,本质上是同一类"错误":调用者没有满足被调用者(函数/动词)预先声明的参数需求

泰尼埃提出配价理论时,明确借用的就是数学函数这套框架——动词是运算符,名词短语是它的操作数,句子则是这次"函数调用"最终求出来的值。

四、把函数框架套进句子结构:论元、题元角色、补足语

有了"动词即函数"这个起点,句法学里一整套围绕它展开的术语,都可以在编程里找到对应物。

4.1 论元(Argument)= 实参

give("She", "him", "a book")

"She""him""a book" 就是传入 give 这个函数的实参——在语言学里,这些实际出现在句子中、满足动词配价要求的名词短语,就叫论元(argument)

4.2 题元角色(θ-role)= 参数类型标注

编程语言允许我们给每个参数标注类型,规定它该是什么样的值:

function give(
  agent: Agent,           // 谁发出动作
  recipient: Recipient,   // 谁接收
  theme: Theme             // 被给予的东西
): GivingEvent

Agent(施事)、Recipient(接受者)、Theme(客体)这些类型标注,对应语言学里的题元角色(θ-role)——规定每个论元在事件里扮演什么语义角色。传入类型不匹配的论元,句子在语义上就会显得怪异,即便语法结构完全合法:

#The rock gave him a book.   // "The rock"语义上很难承担 Agent 这个角色

4.3 配价(Valency)= 函数的参数个数

function sleep(subject: Agent): Event                            // 一价
function read(subject: Agent, object: Patient): Event             // 二价
function give(subject: Agent, recipient: Recipient,               // 三价
              object: Theme): Event
function put(subject: Agent, object: Theme,                       // 三价
             location: Location): Event

传统语法说的"不及物动词""及物动词""双及物动词",正是这份参数列表长度不同的粗略说法。配价理论只是把这份"函数签名"完整地写了出来,不再停留在"及物/不及物"这种二元标签上。

4.4 补足语(Complement)= 参数在调用语句里的具体写法

论元规定的是"语义上必须有什么参与者",补足语则是这个参与者在句子里实际的句法形式——是一个名词短语、一个介词短语、还是一个从句:

I know the answer.              // 补足语是名词短语
I know that he is right.        // 补足语是从句
I want to leave.                // 补足语是不定式

三句话里动词的"语义配价"没有变,变的只是补足语在句法上呈现的形式——就像同一个参数在编程里可以传入不同类型的值(只要符合接口约束)。

4.5 附加语(Adjunct)= 可选参数

function eat(
  agent: Agent,
  object?: Patient,      // 可选参数
  location?: Location,   // 可选参数
  time?: Time              // 可选参数
): Event
He eats.                          // 一价用法,合法
He eats an apple.                 // 二价用法,合法
He eats an apple in the kitchen.  // 可选参数不传也合法

in the kitchen 不是 eat 语义上要求的参与者,去掉句子依然完整——这正是"可选参数"不传也能正常求值的编程行为。语言学把这类"可去掉"的成分叫附加语(adjunct),跟"论元"形成对照。

4.6 函数重载(Overloading)= 动词变价

同一个动词在不同上下文里"变价",等价于同一个函数名注册了多个签名不同的重载版本:

function eat(agent: Agent): Event                          // 重载 1:一价
function eat(agent: Agent, object: Patient): Event          // 重载 2:二价

使役交替(causative alternation)则更进一步,是参数位置本身发生了重新绑定:

function break(agent: Agent, object: Patient): Event   // He broke the window.
function break(object: Patient): Event                  // The window broke.

第二个 break 里,原来处于宾语位置的参数"升级"占据了主语位置——这在编译器实现里,类似于同一个函数名底层绑定了两套完全不同的调用逻辑。

4.7 系动词(Copula)= 恒等函数 / 透明中间层

be 这类系动词,语义上几乎是空的,它不像 givebreak 那样自带一份实义配价要求,而更像一个只做参数转发、自己不处理业务逻辑的中间层函数:

function be(subject: Entity, predicate: Predicate): State {
  return predicate(subject);   // be 本身不添加语义,只负责转发调用
}

be("She", happy)   // 等价于直接调用 happy("She")

真正携带语义配价的是表语——上面例子里的 happy 才是"形容词函数",它自己要求一个论元(经历者);be 只是把这次调用用合法的英语语序包装出来,顺带挂上时态和人称这些语法屈折信息,就像一层只做参数转发、不改变业务逻辑的中间件。

五、总览:句法术语与编程概念的对照表

语言学术语 编程/数学类比 回答的问题
函数(数学) 动词(语言学最初的灵感来源) 一个规则需要几个输入才能求值?
配价(valency) 函数签名 / 参数个数(arity) 这个动词要求几个参数?
论元(argument) 实参(passed-in values) 实际传入的是什么?
题元角色(θ-role) 参数类型标注 每个参数扮演什么语义角色?
补足语(complement) 参数在调用语句里的书写形式 句法上怎么实现这个参数?
附加语(adjunct) 可选参数 不传也能正常求值的部分
动词变价 函数重载(overloading) 同一个函数名注册多套签名
系动词 恒等函数 / 透明中间层 自身不产生语义,只做参数转发

六、这套类比为什么成立,而不只是巧合的附会

"argument"这个词从数学、到编程、再到语言学,始终指向同一件事:一个中心算子(函数/动词)所要求的、用来使其"求值完整"的输入。泰尼埃在提出配价理论时,直接借用的就是这套数学函数的语言——动词是运算符,名词短语是操作数,句子则是这次"调用"最终求出的值。

这不是后人牵强附会的类比,而是配价理论从诞生之初就自带的血统:句法语义学关心"一个中心成分需要哪些参与者才能构成完整意义",函数式编程关心"一个函数需要哪些参数才能返回一个值"——二者共享的,正是同一套关于"规则与输入"的底层逻辑。

posted @ 2026-08-17 13:11  talentzemin  阅读(16)  评论(0)    收藏  举报