在電腦科學領域,semantics 翻成「語意」是好的中文翻譯嗎?

之前在認真讀 ECMA-262 ,一開始遇到最大的問題就是我連標題都看不懂什麼意思:Runtime Semantics: EvaluationStatic Semantics: BoundNames

我在心裡把 semantics 翻成「語意」,得到「執行期語意:求值」,結果每個字都認識,合起來不知道在說什麼。XD

後來自己摸索才慢慢弄懂那到底是在講什麼。這個經驗讓我認真研究了一個問題:在電腦科學領域,semantics 翻成「語意」,是好的中文翻譯嗎?

這篇文章將會討論:

  1. 怎麼理解今天的規格書和工程英文中 semantics 這個字
  2. 回溯這個詞的概念演變,看它歷史上怎麼從哲學到電腦科學被使用
  3. 在理解了這些脈絡,瞭解它真正的意義後,來檢查中文的「語意」翻譯是不是能夠表達

Semantics 在技術文件裡指什麼

結論先講,在今天的規格書和工程英文裡,semantics 的意思可以理解成:

一段語法結構(或一個操作、一個 API)的 semantics,就是「它實際上會做什麼」的定義或約定。

例如:

  • ECMA-262 在書寫慣例一節明文寫著:“These algorithms are used to precisely specify the required semantics of ECMAScript language constructs.”(這些演算法用來精確規定 ECMAScript 語言結構所要求的 semantics。)
    • Runtime Semantics: Evaluation 可以讀成「本節用演算法步驟定義:這個語法結構在執行期被求值時,會發生什麼」。
    • Static Semantics: Early Errors 也是類似的用法,只是「做什麼」的是 parse 階段的引擎:Static Semantics 定義引擎拿到這段結構時要做哪些檢查。
  • ISO C 標準描述每個語言結構的小節,固定分成 Syntax/Constraints/Semantics 三段,Semantics 段寫的就是執行行為,例如迴圈(C99 §6.8.5):“An iteration statement causes a statement called the loop body to be executed repeatedly…”。而整份標準的行為描述建立在一台抽象機器上(§5.1.2.3):“The semantic descriptions in this International Standard describe the behavior of an abstract machine…”——semantic descriptions 描述的是什麼,標準自己說了:behavior。

Semantics 怎麼會指「行為」?

我們可以從語源歷史來考察 semantics 被怎麼用、在什麼脈絡、指什麼?

必須先說明的是,我不是符號學、邏輯學、語言哲學或程式語言理論的專家,沒有系統讀過這些領域的文獻。所以下面的考察,只適合理解成一個對這個詞的來歷好奇的工程師做的筆記:我找網路上查得到的材料、盡量確認它們在該領域算重要文獻、看它們實際怎麼使用 semantics,再試著把觀察串成一條脈絡。歡迎指正。

1883:語言學開始使用:「意義的研究」

語言學家 Michel Bréal 在 1883 年造出法文 sémantique,1893 年進入英文,指「語言中意義的研究」,取代了更早的 semasiology(Etymonline)。這種用法延續到一百多年後,一般辭典的定義仍然在這個範圍:American Heritage Dictionary 收的定義是「1a. The study or science of meaning in language」(語言中意義的研究)和「2. The meaning or the interpretation of a word, sentence, or other language form」(字詞、句子或其他語言形式的意思或詮釋)。在語言學和日常英文裡,semantics 的用法就是這兩個:語言中詞語的意思,或研究這個的學科。

1930–40 年代:符號學與邏輯學——「符號與其指涉對象的關係」

就我查到的資料,syntax/semantics 這組對照在進入電腦科學之前,已經在哲學中使用。例如在符號學領域,Charles Morris 的《Foundations of the Theory of Signs》(1938)把符號研究三分:syntactics 指符號與符號之間的形式關係、semantics 指符號與其指涉對象的關係、pragmatics 指符號與使用者的關係。

另外 semantics 這個字也可見於邏輯學。Tarski 的〈The Semantic Conception of Truth and the Foundations of Semantics〉(1944,發表於 Philosophy and Phenomenological Research;Internet Encyclopedia of Philosophy (IEP) 的介紹)提到:

“Semantics is a discipline which, speaking loosely, deals with certain relations between expressions of a language and the objects (or ‘states of affairs’) ‘referred to’ by those expressions.”

(Semantics 是一門學科,粗略地說,處理語言的表達式與這些表達式所「指涉」的對象(或「事態」)之間的某些關係。)

在這一站,semantics 是處理「表達式與其指涉對象之間的關係」的學科,研究的對象是名字、句子、方程式這類符號與其所指事物的對應。

1959–1960:進入程式語言規格——「語言定義的另一半」,內容是行為

這組現成的對照進入電腦科學,我查到最早的紀錄是 Backus 的會議論文(UNESCO ICIP,巴黎,1959),標題就叫〈The Syntax and Semantics of the Proposed International Algebraic Language of the Zurich ACM-GAMM Conference〉——這組對照直接掛在標題上。但後來的學者認為,這篇真正做到形式化的只有 syntax 那一半。

隔年,ALGOL 60 報告書把這組對照變成規格書的版面結構。ALGOL 60 不是最早的程式語言——FORTRAN(1957)比它早——但它的報告書是「語言定義」這個文類的原型:公認程式語言史上第一套形式語法記法的 Backus–Naur Form,就是在 ALGOL 的定義工作中誕生的(Backus 1959 年提出,Naur 在報告書中改良定案,因此以它們命名);Hoare 後來在〈Hints on Programming Language Design〉(1973)給它的評價常被引用:“Here is a language so far ahead of its time that it was not only an improvement on its predecessors but also on nearly all its successors.”(這個語言遠遠超前它的時代——它不只是對前輩的改進,也是對幾乎所有後繼者的改進。)今天的語言規格書,文體上大多是它的後繼者。

這份由 Backus、Naur 等十三人署名的語言定義,每個語言結構的小節都拆成「Syntax」(用 BNF 形式化)和「Semantics」(用英文散文描述執行時會發生什麼)兩段。例如 for 語句(§4.6)的 Semantics 開頭是 “A for clause causes the statement S which it precedes to be repeatedly executed zero or more times.”(for 子句使它前面的敘述 S 被重複執行零次或多次。)把這句跟本文開頭引過的 C99 迴圈 Semantics——“An iteration statement causes a statement called the loop body to be executed repeatedly…” 並排看:今天規格書的 Syntax/Semantics 版面,是從 ALGOL 60 一路繼承下來的,連句式都幾乎沒變。就我能查到的範圍,這是 semantics 出現在程式語言規格書裡最早的用法——特別值得注意的是:從 1960 年一開始,規格書的 Semantics 段寫的就是「執行時會發生什麼」。這個位置上的 semantics 不是後來才「變成」行為義,它從一開始就是行為描述,只是有不同的用詞和形式化程度。

總結這個時期:Syntax/Semantics 的對照不是 ALGOL 60 發明的,它被用在工程文件之前,已經是哲學上使用的一組區分。ALGOL 60 做的,是把這組區分拿來當規格書的結構,並在 Semantics 那一格填入「執行時會發生什麼」——「行為」就是從這裡開始跟這個詞綁在一起的。

還有一件事也是從這裡開始的:這個詞講的東西變小了。在語言學和邏輯學那兩站,semantics 是一門學問的名字;到了 ALGOL 60,它先是「一個語言的定義的其中一半」,版面再把這一半切開,一個語法結構分到一小段。從此就能說某個結構的 semantics——for 語句的 Semantics 段,講的就只是 for 語句會發生什麼。今天 ECMA-262 拿 Runtime Semantics: 當每一節的標題,就是這個用法一路傳下來的。

1967–1981:formal semantics 研究——把散文的那一半變嚴格

ALGOL 60 只把 Syntax 那一半做嚴格了,但 Semantics 那一半還是形式化不足,描述無法保證各家實作相容——Hoare 在〈An Axiomatic Basis for Computer Programming〉(1969)第 6 節開頭就說:“It has been found a serious problem to define these languages with sufficient rigour to ensure compatibility among all implementors.”(事實證明,要把這些語言定義得夠嚴格、以確保所有實作者之間的相容性,是個嚴重的問題。)

1960 年代開始的 formal semantics 研究,就是要把 Semantics 那一半也變嚴格——把「一段程式的 meaning 是什麼」當成正式的研究問題來回答。這個問題沒有出現單一答案,而是分成三條路線;路線之間差在哪,放到本節結尾再總結。這裡每條路線挑一篇文獻,只問同一件事:論文裡的 semantics 是怎麼用的——在什麼脈絡出現、指什麼?

挑這三篇的理由很單純:它們被各自的路線當成源頭。前兩篇的作者名字後來直接變成路線的稱呼——Floyd 和 Hoare 的做法被合稱 Floyd–Hoare logic,Scott 與 Strachey 的做法被稱作 Scott–Strachey semantics;第三篇 Plotkin 的講義,則在二十三年後被 Journal of Logic and Algebraic Programming 全文重印,當成經典保存。

Floyd(1967)〈Assigning Meanings to Programs。他導言裡 semantics 登場的句子,講的是這個東西可以被「定義」出來、而且不必靠機器:

“…the proposal that the semantics of a programming language may be defined independently of all processors for that language, by establishing standards of rigor for proofs about programs in the language…”

(……本文提議:程式語言的 semantics 可以獨立於該語言的所有處理器來定義——方法是為「關於程式的證明」立下嚴格標準……)

再看形容詞 semantic 的用法:“A semantic definition of a programming language, in our approach, is founded on a syntactic definition.”(在我們的做法裡,程式語言的 semantic definition 建立在 syntactic definition 之上。)——semantic definition 和 syntactic definition 成對出現,正是 ALGOL 60 版面上那組對照。所以 Floyd 的 semantics 是「語言定義中 syntax 以外的那一半」,而他倒進這一半的內容是證明條件:程式的 meaning 落實成 “If the initial values of the program variables satisfy the relation R₁, the final values on completion will satisfy the relation R₂.”(若初始值滿足 R₁,完成時的最終值滿足 R₂)這種可證明的輸入輸出關係。

Scott 與 Strachey(1971)〈Toward a Mathematical Semantics for Computer Languages。問的還是同一個問題——程式的 meaning 是什麼——但答案刻意繞開機器。摘要第一段把動機和主張一次講完:

“Compilers for high-level languages are generally constructed to give the complete translation of the programs into machine language. As machines merely juggle bit patterns, the concepts of the original language may be lost or at least obscured during this passage. The purpose of a mathematical semantics is to give a correct and meaningful correspondence between programs and mathematical entities in a way that is entirely independent of an implementation.”

(高階語言的編譯器,一般會把程式完整翻譯成機器語言。但機器不過是在撥弄位元的排列組合,原語言的概念可能在這趟翻譯中遺失、或至少變得模糊。Mathematical semantics 的目的,是在程式與數學實體之間建立正確而有意義的對應——而且這個對應完全獨立於任何實作。)

所以在這一篇裡,一段程式的 meaning 是它對應到的數學物件。導言用一個比喻說明:2+241+(1+1+1) 是三個不同的符號串,卻指向(denote)同一個數——解釋這種等價「是 semantics 的任務之一」(“The problem of explaining these equivalences of expressions…is one of the tasks of semantics”)。這套「符號指向物件」的講法從哪來,他們自己說了:“To borrow the relevant terminology from logic…”——術語是明著跟邏輯學借的。換句話說,這一派是把 1930–40 年代那一站的 semantics——符號與其指涉對象的對應——整套搬進程式語言:程式是符號,指涉物是數學物件。

對本文的問題來說,這一篇最重要的地方在反面:「meaning=執行過程」正是他們要排除的定義方式。摘要已經說對應要「完全獨立於任何實作」,結論更直接點名批評抽象機器式的定義:

“Sometimes the translation scheme is useful, but usually a full translation, say into the language of an ‘abstract’ machine, makes it hard to discuss the features of the original language in isolation.”

(翻譯式的定義有時有用,但把語言完整翻譯成某台「抽象」機器的語言,通常會讓人難以單獨討論原語言本身的特性。)

在他們手上,位階是反過來的:mathematical semantics 是「評判實作的標準」(“the standard against which to judge an implementation”)——不是實作定義了意義,而是意義用來檢驗實作。這條路的難處他們也承認了:一個帶迴圈、賦值的程式到底指向什麼數學物件並不顯然,需要的結構「無法用普通的集合論手段構造出來」(“such a domain cannot be constructed by ordinary set-theoretical means”),Scott 得先發明新的數學工具。指涉物不是現成的,得先造出來——但守住的立場很清楚:meaning 不必然是行為。

Plotkin(1981)〈A Structural Approach to Operational Semantics,operational semantics 這一派的集大成。開頭第一句的動詞值得注意:“It is the purpose of these notes to develop a simple and direct method for specifying the semantics of programming languages.”(這份講義的目的,是發展一套簡單直接的方法來 specify 程式語言的 semantics。):specify 是規格書 spec 的動詞,而 semantics 就是被規格化的對象。填進去的內容他講得最直白:

“Clearly systems have some behaviour and it is that which we wish to describe. In an operational semantics one focuses on the operations the system can perform.”

(系統顯然有某種行為,而我們想描述的正是行為。在 operational semantics 裡,注意力放在系統能執行的操作上。)

程式的 meaning,是它引起的一步步狀態轉移(transitions)。他還補了一句對本文特別重要的話:這個方法「甚至可以視為對慣常的非正式自然語言描述(的許多面向)的直接形式化」(“the method is even intended as a direct formalisation of (many aspects of) the usual informal natural language descriptions”)——所謂「慣常的非正式自然語言描述」,就是規格書裡那種一步一步的散文。

把三篇並排,這個時期可以歸納出三件事。

第一,三篇用這個詞的方式一致:semantics 是一個要被做出來的東西。 Floyd 說它可以被 define,Scott 與 Strachey 說目的是 give 一個對應,Plotkin 說要有方法 specify 它。它不再只是一門學問的名字,而是那門學問要交出來的東西。

第二,三篇講的都是「一整個語言」的 semantics。 引文裡的受詞都是 the semantics of a programming language——一份把整個語言蓋起來的定義;Scott 與 Strachey 標題裡的不定冠詞(a mathematical semantics)也是這個意思:這種定義做得出一份一份的,還能比較好壞。不過三篇動手的方式,都是照著語法一條一條給——Scott 與 Strachey 的 semantic equations 一條對一個語法子句,Plotkin 的 structural 指的就是照語法結構逐條寫規則——所以「一整個語言的 semantics」和「單一結構的 semantics」是同一份定義,一個是整本,一個是其中一頁。

第三,三篇填進那份定義的東西不一樣: Floyd 填的是可證明的輸入輸出關係(後人稱 Axiomatic)、Scott 與 Strachey 填的是數學物件(Denotational)、Plotkin 填的是一步步的狀態轉移(Operational)。與其說這是同一題的三個互斥答案,不如說他們各自要 meaning 替自己做不同的工作:拿來證明程式正確、拿來當數學研究的對象、拿來描述系統的行為。彼此之間不是沒有意見——上面就看到 Scott 與 Strachey 點名批評抽象機器式的定義——但這三條路線最後不是誰淘汰誰,而是各自留在最合用的地方。這就是下一站。

1960 年代至今:三條路線各有用途,規格書走的是 operational 這條

三條路線後來各自留在最合用的地方:要證明一段程式符合規格,用 Floyd–Hoare 這一脈的邏輯;做理論研究,常用 denotational 的數學物件;寫語言規格書、做直譯器,用 operational 的逐步描述。這個詞一直保持著邏輯學給它的形狀——符號與指涉物的對應:程式是符號,semantics 是它對應到的東西;三條路線的差別,只在對應到的東西是什麼——可證明的條件、數學物件,還是一步步的轉移。

本文開頭所舉的語言規格書,走的是 operational 這條:ECMA-262 的 Runtime Semantics 演算法步驟、C 標準的抽象機器,寫的都是「一步一步會發生什麼」——Plotkin 自己說了,他的方法就是把這種自然語言直接形式化。所以「semantics=它實際上會做什麼」那個開頭給的答案,適用範圍是規格書和工程日常英文;翻開程式驗證或理論的文獻,semantics 指的可能是另外兩種東西。

層級上也有一個變化:工程日常英文說的 semantics,幾乎都站在「單一操作、單一結構的行為」這個層級——move semantics、the semantics of await——而且 of X 的 X 不再限於語法結構,API、操作都能掛上去。〈Semantics 在技術文件裡指什麼〉開頭那個定義,寫的就是這一層。

到此,把時間軸整個順起來就是:語言學的「意義」(1883)→ 符號學與邏輯學的「符號與其指涉對象的關係」(1930–44)→ ALGOL 60 首先在規格書裡把 Semantics 段寫成行為描述,也讓這個詞可以指到單一結構(1959–60)→ 理論研究把 Semantics 那一半變嚴格、三條路線各自成形(1967–81)→ 規格書延續 ALGOL 60 到 operational 這條線,累積成英語圈工程文件的習慣用語。

所以,「語意」是好的翻譯嗎?

先從英文的日常用法談起。

semantics 在 Oxford Learner’s Dictionaries 的兩個意思是「字詞與片語的 meaning 的研究」和「字詞、片語或系統的 meaning」;Longman 是「字詞或表達式的 meaning」,但特別標成 formal。所以一般會說 I know what you mean,不會說 I understand your semantics;一般會說 These two sentences mean the same thing,但只有進入語言學或邏輯學的語境,才會說它們 have the same semanticsare semantically equivalent

中文的「語意」涵蓋的範圍就不太一樣。例如下面這些句子:

  • 「不要曲解我的語意。」
  • 「同一句『好啊』,換個語氣,語意可以完全相反。」
  • 「這段文字前後語意不連貫。」
  • 「這句話語意不清。」

它們自然的英文不是 semantics,而是 What he meant was a refusalDon't twist what I mean“Sure” can mean the opposite in a different tone(The meaning of) this sentence is unclear/ambiguous。這裡指的不是字句按照語言規則固定表示什麼,而是某個人在特定情境下,藉這句話想表達什麼。連「這句話語意不清」「這兩句的語意相同」這類看似只談句子的說法,自然的英文通常也是 The meaning of this sentence is unclearThese two sentences mean the same thing,不是 semantics。

就像教育部《重編國語辭典修訂本》對「語意」的解釋:「話中所包含的意思」,日常中文的「語意」很自然地跨進說話者、語氣和情境這一側。

所以我們可以說,英文 semantics 的一般用法本來就偏向 Morris 分給 semantics 的那一側:字詞、句子、符號與其意義,而不是特定說話者在情境中的用意。Morris 的三分法把這個傾向畫成明確界線:semantics 管符號與指涉對象的關係,pragmatics 管符號與使用者的關係。後來的邏輯學與 formal semantics 繼承前一側,刻意不拿「這個人此刻想暗示什麼」來決定符號本身的意義。Oxford 對 pragmatics 的解釋,就是研究語言如何在特定情境裡表達某個人真正想說的意思,尤其是實際字句看起來另有所指的時候。中文「語意」的日常用法卻把兩側都包了進來。

所以,雖然一般中英文使用者都不知道 semantics 在專業領域的歷史,但英文讀者要把「語言形式與意義」這層認識延伸到語言學或電腦科學,並沒有什麼特別困難;而中文使用者得先把「說話者在情境中想表達什麼」這個熟悉的方向擱到一旁。

但其實中文並不是沒有這種表達能力:指著符號問「它表示什麼」、指著程式問「這段在做什麼」「執行起來會發生什麼」,都是日常中文最貼近 semantics 的表達。但這些都是述句,如果想用一個名詞指稱,中文就沒有哪個已經有的詞彙,是剛好停在 semantics 的範圍內,沒有跨到 pragmatics。

附帶一提,如果在國家教育研究院樂詞網的查詢 semantics,可以看到同時列出「語意」「語意學」「語義學」,電子計算機名詞中還可見「形式語意」「查詢語言語意」這類寫法。從國家圖書館館藏,也可以看到較早且較主流的 semantics 翻譯是「語意」(例如,用「語意學」檢索書名,可見 1957 年香港出版的《語意學概要》和 1963 年台灣出版的《語意學與真理》,「語義學」就要到 1986 年中國出版的《語義學導論》,或 1995 年台灣出版的《現代語義學》。

老實說,我個人認為「語義」確實比較接近 semantics 的意涵。「意」很容易連到人想表達的意思,「義」則比較容易連到語詞或符號本身所表示的內容。但「語義」似乎不是台灣一般人在日常生活中本來就這樣使用的詞,教育部辭典只收「語意」「語意學」「詞義學」。或許它是專業領域在翻譯時為了保住概念界線,另外造出並定義的術語。

所以我們可以說 semantics 的中文翻譯,實際情況是:「語意」不是 semantics 的好翻譯,卻是台灣最通行的既有譯名;「語義」保留的概念邊界比較好,卻是較不主流的專業術語;日常中文真正自然又精確的對應,則常常不是名詞,而是「X 表示什麼」「X 實際上會做什麼」這類述句。

那怎麼辦

既然名詞沒有適合的東西可用,或許就不要硬套名詞。

回到本文開頭那個場景——讀 spec、讀工程英文、寫工程中文。回溯歷史時說過,規格書走的是 operational 這條路線;在這個場景裡,semantics 指的就是行為——求值時它會發生什麼,或 parse 階段引擎拿到它要做什麼。所以至少在這個情境,都可以改用我們本來就會說的:「這段 code 在幹嘛」。在這樣的脈絡中,semantics 幾乎總是以「semantics of X」的形態出現,於是我們可以把這讀成「X 在幹嘛」。幾個例子:

原文讀成
Runtime Semantics: Evaluation本節定義「求值」:這個結構執行起來實際上會做什麼
Static Semantics: Early Errors本節定義「early errors」:哪些寫法引擎在 parse 階段就要擋下
the syntax and semantics of do {} while ()do {} while () 怎麼寫才合文法/執行起來會發生什麼
move semantics「搬移」這個操作實際上做什麼的約定
the semantics of awaitawait 實際上做什麼
semantics-preserving refactor不改變行為的重構

或者既有術語「語意」也可以沿用,但我們可以特別處理它跟日常意思之間的落差。所以我們有以下兩個選擇:

  1. 使用名詞,但首次出現時把 semantics 和白話定義一起交代。可以直接用英文 semantics,例如「semantics——也就是『做這件事時實際上會發生什麼』的約定」;也可以沿用「語意」或「語義」的中文翻譯,但第一次寫成「語意(semantics)」或「語義(semantics)」,並立刻說明本文的用法。這樣既接得上既有教材與術語表,也不要求讀者靠日常語感猜。英文課堂這樣做,中文教材也是——例如陳鍾誠的〈高階語言的語義理論〉開頭就直接規定:「語義理論說明的是對應語法的意義,也就是程式該如何執行的規範。」
  2. 不使用名詞,把意思攤開成白話:「行為」「保證」「你拿到什麼」。我最近改寫一篇講 React latest ref pattern 的文章時就走這條路——原本寫「同一個值的兩種時間語意」,改成「畫面要 render 那一刻的值,長壽命 function 要呼叫那一刻的值」。不倚賴「語意」之後,句子反而更準:所謂「兩種語意」,攤開來本來就是「兩個不同時刻的取值」。

參考資料