Skip to content

一點哲學探討

DANGER

本頁面充滿了個人主觀意見。請批判性閱讀。

You could have invented Moran——魔然設計的邏輯

魔然方案可以看作是沿着「智能拼音掛接」路子走到盡頭的產物。具體來說,整個設計是從一個根本出發點開始,依邏輯不斷推演得到的產物:

  • 想打詞
  • 爲了打詞輕鬆,詞語編碼應該以音碼爲主
  • 爲了詞語碼長短,以雙拼爲基礎
  • 爲了詞語編碼空間儘可能大(雙拼離散較差),選擇不定長編碼
  • 爲了不定長編碼、兼容純雙拼、自動造詞等功能,選擇基於整句實現
  • 爲了解決整句的不確定性(在開啓了用戶詞庫時),設置固定簡碼
  • 爲了讓簡碼的條反可以延續到整句,整句必須支持輔助碼混輸,並且整句用的輔助碼必須和簡碼中用到的形碼是一致的

(其實上面每一步都值得寫一小節來解釋我的理由,不過這裏就從略了。)

因此,整個魔然方案是完整的一體,各模式其實並不能分開來看。(除了輔篩是例外,它可以乾淨利落地拆成別的方案。)

The Consistency Question——簡繁字形的兼容性

雖然上面說得一套一套的,但是魔然最初的出發點並不是「我覺得市面上的方案都不適合我!我要做一個最強的輸入方案!」,而是一個小小的想法:「我要實驗一下有沒有方案可以同時兼容簡繁字形!」——當時,我還在使用形碼。

這個想法最初來自於 2022 年筆者對小鶴音形的嘗試,發現雖然小鶴音形的碼表是簡體字,但是轉換成繁體後,大部分字的編碼其實不變。再加上考慮另一個極端:純音碼可以無縫兼容簡繁字形。那是不是只要形的部分越少,兼容性就越好?

在初期嘗試的過程中,我很快確立了部首優先的原則,即第三碼應該是部首,不是拆字拆出來的第一個部件。這是因爲它有很多我最初甚至沒有預料到的好處:

  1. 漢字中部首不出現在左邊或上面的情況比想象中得多,可以提高三碼離散。
    1. 如:「栽載哉」分別可以用 zlm zli zlk 輸入,「墓幕暮慕募」分別可以用 mut muj muo mux mul 輸入,「形型」分別是 xyp 和 xyt 而不會被「开」干擾
  2. 部首和字義有強關聯,拆字時往往不用思考字形,而是只需要想到字義,就能打出這個字。
    1. 如:壟(與土有關),攀(與手有關),憂(與心有關),暮(與日有關)
  3. 部首往往可以恰好把一類字的不同字形歸類在一起。
    1. 如:「勸勧劝」都是qrl,「憂忧」都是ybx

最初的魔然字詞碼表是同時容納簡體和繁體的,但是後來發現雖然整體上一致性很高,但是高頻字中還是有不少字三碼不一致。很多用戶反饋自己不會繁體字,需要一個純簡體的碼表,於是這才另外製作了簡化字版本。——筆者雖然日常打簡化字不少,但是依然使用繁體版,所以筆者認爲只要您不抗拒繁體字(碰到三碼不一致的情況時,您的第一反應是「又學到了」而不是「又被坑到了」),都可以先嘗試嘗試繁體版,也許有意外之喜呢。

因此,我認爲關於簡繁字形的實驗本身已經完結了。結論是:成功!雖不算 100% 完美,但完全可以接受,甚至超出預期。

The Unreasonable Effectiveness——爲什麼魔然如此好用

背景

如果您讀了上兩節,可能會注意到魔然一開始並不是爲了「降低碼長」「提高打字速度」等目標設計的,而是作者個人的一個小小實驗品,單純是爲了實驗音形碼對簡繁字形的兼容性。從另一個方面說,也是爲了解決作者個人一個極小衆的需求。

而其他設計,也都恰好只是這個需求催生來的——我只是希望音的部分夠多(哪怕我長時間不用,也可以快速撿起來),而恰好我想少點選重,所以選擇以「掛接用法」爲藍本而已。

當時(2023年初),我使用的是一款名爲虎碼的形碼方案。我做魔然單純是一個實驗,打算在得到結論後,就回到虎碼。唯一沒想到的是,這個實驗竟然相當成功,以至於我逐漸「樂不思虎」,在魔然扎根了,至今已經使用快 2 年。

但與之相對的是一個顯然的悖論:自然碼本身並不是一個追求性能的方案。單字重碼率不低,詞重更是不低。以通常視角來看,它不應該好用啊!

理論預言錯得這麼離譜,讓我不得不做了一些分析:魔然究竟爲什麼好用?傳統的評價指標到底「錯」在哪?

或許,我們選擇的指標根本不對——一個新的輸入法評價指標

筆者認爲,在全拼都能滿足大部分用戶的大背景下,漢字輸入最重要的指標已經不是硬性的「碼長」「確定性」等,而是一種(虛無縹緲的)「輕鬆感」「流暢感」,或者說,是實際輸入中「輸入法本身存在感的稀薄程度」。

Note:我認爲任何輸入法方案作者都應該注意到這一點:如果輸入法評測所用的硬性數據指標真的那麼重要,那全拼根本不應該成爲最流行的輸入法。

因此,任何評價輸入法的指標都應該接受全拼檢驗:你所預言的「好用程度」必須與全拼的流行程度一致。假設你選取的評價標準得到的結論是「全拼是最差的輸入法」,那必須解釋爲什麼你的預言和現實不符。

如果以「輸入法本身的存在感稀薄程度」爲標準,我們可以立即注意到:

  1. 音碼(以智能拼音和智能雙拼爲代表)的存在感在選重時會顯現出來。
  2. 形碼的存在感在 (1) 拆字 (2) 選重 時顯現出來。

並且存在感會隨時間累加:上面提到的事件如果耗時越長,存在感就越強。

因此,爲了讓輸入更流暢,我們需要最小化拆字和選重的負擔。下面我們來看看各輸入法是怎麼做的:

  1. 智能拼音:不斷提高智能化程度,通過大量數據分析字詞頻率和關聯,減少選字頻率
  2. 形碼
    1. 針對拆字的存在感:
      1. 強調訓練高頻字條反,從而降低拆字頻率
      2. 設計更大的字根從而讓拆字更直觀,從而降低拆字用時
    2. 針對選重的存在感:設計更大的字根、更怪的拆字、亂序分佈字根、出簡讓全、出簡不出全等方法,從而降低選重率
      1. 或者可以直接打純單,這樣就完全沒有詞重帶來的存在感了

那麼魔然所屬的雙拼加形類別呢?

  1. 針對拆字的存在感:
    1. 通過設置簡碼,降低了拆字頻率(一簡和二簡不需要拆字)
    2. 通過只取首末、字根音托,降低拆字耗時(思維負擔的減少體現在時間縮短上)
    3. 通過置前兩碼爲音碼,拆字與輸入音碼可以同步進行,降低拆字的實際耗時
  2. 針對選重的存在感:
    1. 輸入整句時,可以復用智能拼音的算法和一切成果
    2. 通過輔助碼,可以降低選重的耗時
    3. 通過有策略地拆單,可以降低選重的頻率

總的來說,雙拼加形是對智能拼音的一個嚴格改進:它具有智能拼音的一切優勢(從而有相同量級的選重頻率),又有智能拼音所不具有的更多能力(這些能力可以降低選重頻率),代價是一點學習成本。

在這裏,我提出一個初步的量化方法:

存在感 = 選重頻率 * 平均選重耗時 * w1 + 拆字頻率 * 平均拆字耗時 * w2

(其中 w1 和 w2 是特定的加權係數,表示用戶對這種存在感的厭惡程度:如果用戶極度厭惡拆字(即提筆忘字還覺得這不是個事兒),那麼他可以把 w2 設置爲一個很大的數字。一般來說,爲了討論簡便,不妨就設置 w1 = w2 = 1。)

「存在感」衡量了「僅僅因爲輸入法本身問題、導致用戶額外付出的時間」(對不存在拆字和選重的方案也可以提出類似的指標),而在一個理想的輸入法裏,這個值應該是0。它並不衡量用戶本身導致的輸入錯誤問題(即鍵準不計入計算)。

事實上,在引入一些假設的前提下,存在感的確可以是 0:

  • 智能拼音用戶在合適的文本上,可以做到 0。
  • 形碼用戶對所有字全部條反,只打純單,可以做到 0。
  • 雙拼加形用戶預判所有重碼,單字條反,可以做到 0。

上面的公式中並沒有出現碼長、手感等很多輸入法發燒友熟悉的指標。或許……這並不是一個巧合?事實上,我們可能都有過這樣的體會:用過一個方案,覺得它非常順手,但是絕對速度卻不快;或者用過一個方案,絕對速度不低,但是怎麼用怎麼覺得不爽。

因此,我認爲「存在感」可以較好地從用戶側終端衡量輸入法的實際體感好用程度。每個輸入法的存在感值甚至可以通過實驗測量出來。

  1. 這個指標可以用來測試用戶本身。試設想以下場景:

    1. 某方案事實上是無理碼,故在無外界幫助的情況下,拆字耗時可設想爲無窮大,而用戶不可避免地會碰到之前沒打過的字,需要現拆,或
    2. 某拼音輸入法每打一字都需要選字,且輸入法的順序完全錯誤,使得選字耗時極長

    則用戶必然不會選擇這樣的方案。這意味着,用戶必然存在一個「存在感耐受」的上限。
    上限可以用於選擇最適合用戶的方案:若用戶通過估算或實驗得到了自己的耐受上限,就可以選擇存在感在該上限以下的、性能最佳的輸入方案——也就是對自己來說最優的輸入法。

  2. 這個指標也提供了一個評價方案的新維度。如果在任何情況下,方案A的絕對性能都較方案B更差,且存在感都更高,那麼我們就有必要嚴肅地質疑這樣的方案的意義爲何了。

  3. 這個指標很有可能是不完備的。在本文中,我們假設 w1 和 w2 都只是用戶本身的偏好,但這可能不對。例如,對拼音用戶來說,選重是日常生活的一部分,所以碰到選重時不會有嚴重的抗拒心理;而對形碼用戶來說,任何一次非預期的選重都會帶來嚴重的負反饋。這意味着上式中的 w1 和 w2 可能還與方案本身有關,而不只與用戶有關。

或許,收益與難度不成正比——爲易學性正名

DANGER

本節和下面的內容還未寫完,不代表最終觀點!

通常來說,我們會覺得收益與難度成正比。因此,一個追求「性能」的初學者會自然而然地忽視掉「易學」方案。但這種忽視對嗎?

我們不妨假設一個人只要使用過一次某種信息(不論是字根鍵位還是讀音),就永久條反了這個信息,從而得出一個最少的「形成條反」的時間下限:

  • 四碼形碼:初次學習時間
    • = 編碼時間 * 總字數
    • = 拆字時間 * 總字數 + 平均字根編碼 * 總字根數
      • 可以進一步分成一二三簡和全碼
  • 音碼:初次學習時間
    • = 編碼時間 * 總字數
    • = 讀音時間 * 總字數 + 讀音編碼時間 * 總音節數
    • = 查詢讀音時間 * 不會讀音的字數 + 讀音編碼時間 * 總音節數
    • ≈ 讀音編碼時間 * 總音節數
      • 在常用字範疇上,可以認爲「不會讀音的字數 ≈ 0」
  • 音形碼:初次學習時間
    • = 編碼時間 * 總字數
    • = (讀音時間 + 判斷簡碼時間) * 總字數 + 讀音編碼時間 * 總音節數 + 拆字時間 * 三四碼字數 + 平均字根編碼時間 * 總字根數
    • = 判斷簡碼時間 * 總字數 + 查詢讀音時間 * 不會讀音的字數 + 拆字時間 * 三四碼字數 + 平均字根編碼時間 * 總字根數
    • ≈ 判斷簡碼時間 * 總字數 + 讀音編碼時間 * 總音節數 + 拆字時間 * 三四碼字數 + 平均字根編碼時間 * 總字根數
      • 理由同音碼

爲了讓這個時間下限更加接近實際時間,可以引入「使用頻度」 ——一個信息用得越頻繁,越不容易忘。標記爲 字根i編碼時間/字根i使用頻度。在假設頻度完全均勻的情況下(最理想情況),字根越多,每字根頻度越低,實際成本增長超過線性。不妨把實際成本作爲編碼要素數 N 的函數,且這個函數增長速度快於 kN,但很有可能小於 kN^2。換句話說,若字根數量翻倍,則學習成本會是原來的2倍還多,但不會到達4倍。

INFO

上式中的 / 表示頻度越低,實際花費的時間越高。但實際生活中很有可能並不是線性關係,而可能是其他某種函數關係。這裏提示讀者不要把 / 當作真正的「除法」,只作爲一種簡寫。

經過估算,可以得到一個粗糙的結論:

  • 難度一般與有關,
  • 一般而言,音形碼難度低於形碼,高於音碼
    • 在特定情況下,
  • 但是當我們考慮詞語輸入時,音形碼難度低於

或許,重碼率沒那麼重要——雙拼加形的特殊性

TODO

打字速度到哪才是頭?——論確定性與性能

TODO

自然碼/魔然本身的特有優勢

TODO

結論

TODO

The Dialectical Reversal——談談「簡繁通打」

很多和我一樣有傳承字輸入需求的用戶,往往要麼使用純音碼,要麼使用純形碼。純音碼暫且不論,形碼則往往只優先考慮一種字形,另一種字形則後置。對於需要經常切換兩種字形的用戶來說極爲不便,因此便產生了所謂的「簡繁通打」的說法:讓簡體字和繁體字的編碼不重碼。例如,「馬」和「马」放在不同的按鍵上。典型的方案有徐碼宇浩碼

INFO

我個人認爲「簡繁通打」是有誤導的宣傳命名。沒有細看定義的用戶容易誤解「只有簡繁通打的方案才能輸入繁體字/簡體字」。但事實並非如此。一個不簡繁通打的方案完全可以收錄整個 Unicode 字集——那當然也可以輸入繁體字。本節討論中暫且繼續使用該命名。

這類「簡繁通打」方案聲稱自己解決了字形切換問題。當然,在一定程度上,的確如此。設若你需要臨時輸入繁(簡)體字,直接打繁(簡)體字編碼即可。這類方案的實質是通過編碼強行將「全等異體字」分離,目標是在無上下文/無模式切換的情況下,快速輸入另一種異體字。

然而,在我看來,此類方案有着以下缺陷:

  • 若設置簡碼,而簡碼空間有限,則必然會優先一種字形。這又重新產生了簡繁之間的不平等性。
    • 一些方案認爲這是必要的妥協,提供多種簡碼表。
    • 一些方案認爲這是嚴重的問題,直接放棄簡碼,用戶應該只打全碼。
    • 還有一些提供簡繁混頻排的簡碼表,但這會降低碼表效率。(我曾見過某方案中「爲為为」中的多個均被設置成一簡。)
  • 需要額外記憶另一種字形的字根映射。若另一種字形用得不多,遺忘後會比較麻煩。
  • 由於簡繁字形編碼不同,如果需要大量輸入另一種字形,則需要建立兩套條反。

由於這些缺陷,私以爲大字根的簡繁通打方案的優化目標,其實受衆很小——大概需要接近 1:1 比例日常輸入簡繁字形,以至於能建立兩套穩定條反而不遺忘。但即使在這種情況下,學習成本也比較高。

問題在於,簡繁之間一般是異體字的關係,而且大部分是全等異體字。所謂的全等異體字就是音義皆同,只有字形不同的一組字,如「連」和「连」就是一組全等異體字。但我們爲什麼一定要「分離」才能「通打」呢?是不是其實「合併」更容易「通打」?以前似乎沒有人提出過這樣的看法。

私以爲答案是肯定的。要支持多種字形,同時還要降低使用負擔,那麼要做的不是「分離」,而應是「合併」。更需考慮到,簡體和繁體只是全等異體字的一小個側面。對於一个字來說,它可以有不止兩種異體。具體選用哪種異體字,是由「正字法」給出的——大陸的規範字、臺灣的正體字、香港用字標準、日本當用漢字表等,都是「正字法」。

假如說,我們恰好可以讓全等異體字重碼(與「簡繁通打」類方案恰恰相反),那「正字法」就可以通過一套配置文件給出。通過簡單的模式切換,就可以輕鬆輸出「簡」「繁」「日」乃至別的正字法標準,同時我們思維上並不做任何切換,並且輸入效率不受影響。

也就是說,我們需要追求的是「全等異體字之間」恰恰應該重碼,而不是全等異體字關係的字之間應該不重碼。

自然碼巧妙的設計幾乎完美實現了這個目標。雙拼的 2 碼音碼和自然碼的「部首優先」規則,使得絕大多數字全等異體字都具有相同的 3 碼。如在使用魔然時打開「字集增廣模式」,往往在輸入 3 碼時,可以看到一大批形似的字,並且一般還真就是異體字關係。如输入 lqe 可以看到「陸陆𲉊𨸪𨽐𨽰」,只有一個「𨻧」不屬其列。更神奇的是,很多異體字 4 碼也真的就剛好重碼(試試輸入 yjtmo)。

總的來說,在異體字處理上,我認爲(受控的)「合」遠遠好於「分」。「分」唯一的好處是不用切換模式,但收益似乎並不比代價更大。所以我不認同「簡繁通打」。

INFO

開放問題:可否設計一種方案,前 N 碼恰好歸類全等異體字的等價類,而輸入 N+M 碼又可以把同一個等價類中的字區分開?