<譯>自由幺半羣

上一篇:極限與餘極限程序員

原文地址:https://bartoszmilewski.com/2...編程

不管是在範疇論中仍是在編程中,幺半羣都是個重要的觀念。範疇對應着強類型的語言,而幺半羣對應着無類型的語言。由於在幺半羣裏你能夠複合任意兩個箭頭,就像無類型語言中你能夠複合任意兩個函數同樣(固然,在你執行程序時可能以一個超時的錯誤而了結)。segmentfault

咱們已經看過幺半羣能夠描述成一個單對象的範疇,在那個範疇裏全部的邏輯都被變成了態射的複合規則。這個範疇模型和更傳統的集合論意義下的幺半羣定義徹底等價,那個定義是說咱們把兩個元素「相乘」獲得第三個元素。這個「乘法」過程能夠被進一步解剖爲先構建一個元素的序對而後把這個序對指定爲一個已有的元素——它們的「積」。app

咱們把乘法的第二部分——把序對指定爲已有的元素——丟掉會發生什麼?好比說,咱們能夠從任意一個集合出發,構建全部可能的序對,而後把它們叫作新的元素。而後咱們用這些新的元素再次構建全部可能的序對,以此類推。這是一個鏈式反應——咱們會不不休止地加入新的元素。這樣的結果是個無限集,幾乎就是一個幺半羣。但一個幺半羣還須要一個單位元和結合律。固然沒問題,咱們能夠添加一個特殊的單位元而且令某些序對相等——剛恰好知足單位元和結合律。函數

讓咱們看看在具體例子裏這是怎麼作的。咱們從一個有兩個元素的集合{a, b}出發。咱們將會把它們叫作自由幺半羣的生成元。首先,咱們添加一個特殊元素e做爲單位元。接着,咱們加入元素的全部序對叫作「積」。ab的積就是序對(a, b)ba的積就是序對(b, a)aa的積就是序對(a, a)bb的積就是序對(b, b)。咱們還能用e構建像(a, e)(e, b)等這樣的序對,但咱們會把它們指定成ab,等等。因此這一輪咱們只添加了(a, a)(a, b)(b, a)(b, b),並獲得了集合{e, a, b, (a, a), (a, b), (b, a), (b, b)}spa

bunnies

下一輪裏咱們會加進來一些像(a, (a, b))((a, b), a)等等的元素。這時咱們就必需要保證知足結合律,因此咱們會把(a, (b, a))指定爲((a, b), a)等等。換句話說,咱們不須要內部括號。code

你能夠猜一下這個過程的最後結果是什麼:咱們會創造出ab的全部可能的列表。實際上,若是咱們用空列表表示e,咱們就會看到咱們的「乘法」和列表鏈接沒有任何不一樣。對象

這種不斷生成可能的元素組合而且作一個最小數目的指定——僅僅爲了知足法則——的構造就叫一個自由構造。咱們剛剛作的就只是用生成元{a, b}構造了一個自由幺半羣blog

Haskell中的自由幺半羣

Haskell中的兩個元素的集合等價於Bool類型,這個集合生成的自由幺半羣等價於[Bool]類型(Bool的列表)。(我故意忽略了無限大列表的問題)排序

Haskell的幺半羣是用類型類定義的:

class Monoid m where
    mempty  :: m
    mappend :: m -> m -> m

這只是在說每一個Monoid必須有一個叫mempty的幺元和一個叫mappend的二元函數(乘法)。單位元(律)和結合律不能在Haskell中表達,必須在每次實例化幺半羣的時候有程序員驗證。

任意類型a的列表構成一個幺半羣的事實由這個實例的定義描述:

instance Monoid [a] where
    mempty  = []
    mappend = (++)

這是說空列表[]是單位元,而列表鏈接運算(++)就是那個二元運算。

就像咱們已經看到的那樣,一個a類型的列表對應着由集合a充當生成元的自由幺半羣。天然數集帶上乘法運算並非一個自由幺半羣,由於咱們指定了太多的積。做爲例子比較一下:

2 * 3 = 6
[2] ++ [3] = [2, 3] // 和[6]不一樣
此處做者舉的例子多少有些使人混淆。在原文的評論區也有不少人和做者討論了該問題,想看相關內容的讀者能夠移步原文評論區。天然數的確不能夠一個自由幺半羣,就算選擇素數集做爲生成元, 2*3=3*2=6這樣的交換律也是在自由幺半羣定義以外的東西。此處做者的例子大概是想說在天然數中 2*3=6,而在自由幺半羣中不能夠把這樣一個乘法算式的結果明確指定爲像 6這樣的某個既有的數字(即這種指定必定不是自由幺半羣所必需的,從而導出的必然不是自由幺半羣),只能表示爲序對 [2, 3]的形式。譯者注。

這很容易懂,但問題是,咱們可否在範疇論中表示這種自由構造,而在範疇論中咱們沒法觀察對象的內部?咱們將會用到咱們的主角:泛構造。

第二個感興趣的問題是,是否任意一個幺半羣都能經過一些,比那些僅僅知足法則的最少數目的指定更多的指定,來從自由幺半羣得到?你會看到泛構造能夠直接獲得它。

自由幺半羣的泛構造

若是你想一想咱們以前有關泛構造的經驗,你可能就會注意到它並非那麼像挑一個最符合某個模式的對象那樣構造對象的。因此若是咱們想用泛構造「構造」一個自由幺半羣的話,咱們必須考慮幺半羣的一整個族而後從裏面挑一個。咱們須要一整個要選取(對象)的幺半羣的範疇。但幺半羣能構成範疇嗎?

讓咱們先把幺半羣看做帶上附加結構的集合,附加結構由單位元和乘法定義。咱們要選一些保持幺半羣結構的函數做爲態射。這種能保持結構的函數被稱做同態。一個幺半羣的同態必須把兩個元素的積映爲這兩個元素像的積:

h (a * b) = h a * h b

並且它必須把單位元映爲單位元。

這個同態的定義就是抽象代數中的定義,注意,等號先後的兩個乘法所在的幺半羣是不同的。譯者注。

好比,考慮一個從整數列表到整數的同態。若是咱們把[2]映爲2,把[3]映爲3,那咱們就必須把[2, 3]映爲6,由於鏈接操做

[2] ++ [3] = [2, 3]

變成了乘法

2 * 3 = 6

如今讓咱們忘掉那些個幺半羣的內部結構,僅僅把它們看做這些對應的態射鏈接的對象。你就能獲得一個幺半羣範疇Mon

好吧,可能剛剛咱們忘掉了內部結構,讓咱們來看一個重要的性質。每一個Mon的對象都能平凡地映爲一個集合。這就僅僅是它地元素組成的集合。這個集合叫作承載集。事實上,咱們不只能把Mon的對象映爲集合,咱們還能把Mon的態射(同態)映爲函數。仍是那句話,如今看起來有些無趣,但立刻就能用到了。這個從MonSet的態射其實是個函子。由於這個函子「忘掉」了幺半羣的結構——一旦咱們到了扁平的集合上,咱們就不會再區分誰是單位元或者關心乘法了——它叫作遺忘函子。遺忘函子常常出如今範疇論中。

咱們如今有了兩種不一樣的看待Mon的視角。咱們能夠像其餘的包含對象和態射的範疇那樣看它。這種視角下,咱們不會看到幺半羣的內部結構。咱們對某個特定的對象所能說的就只有它經過態射和它本身以及其餘對象相關聯。態射的「乘法」表——複合規則——是來源於另外一個視角:做爲集合的幺半羣。就算步入了範疇論咱們也不能徹底丟掉這種視角——咱們仍然要經過遺忘函子使用它。

爲了用泛構造,咱們須要定義一個特殊的性質,這個性質可讓咱們對幺半羣範疇排序而後挑出最好的那個看成自由幺半羣。可是自由幺半羣是經過它的生成元定義的。不一樣的生成元的選擇會導出不一樣的自由幺半羣(一個Bool列表和一個Int列表並不同)。咱們的構造必須從一個生成元的集合開始,因此咱們回到了集合!

這就是遺忘函子可以顯身手的地方了。咱們能夠用它給咱們的幺半羣拍X光片。咱們能夠在這些傢伙的X片上指定生成元。它是這麼工做的:

咱們從一個生成元集合x出發。這是個Set中的集合。

咱們想要匹配的模式由一個幺半羣m——Mon的一個對象——和一個Set中的函數p構成:

p :: x -> U m

其中U就是咱們的從MonSet遺忘函子。這是個奇怪的異質模式——一半在Mon裏一半在Set裏。

想法是函數p會在m的X片中指定生成元的集合。在集合中指定一些點的函數(它們可能會坍縮這些點)有些討厭,不過不要緊。它們都會在泛構造中排序,而這會挑出那個最好的表明。

monoid-pattern

這裏可能有些使人費解,但只要注意到x是已經預先給定的的話,這一切就會瓜熟蒂落:也就是說,函數 p已知一個預先給定的生成元集合 x,而後把 x的每個元素都映爲 m的集合中的某個元素,這就像是從 m的集合中挑一些元素做爲其生成元集,而且這個新集合不能比 x更大。

咱們還必須定義候選者們的排名方式。假定咱們還有另外一個候選者:一個幺半羣n和在它的X片中指定生成元的一個函數:

q:: x -> U n

咱們說mn更好是說存在一個幺半羣的態射(保持結構的同態):

h :: m -> n

它在U下的像(記住,U是個函子,因此它會把態射映爲函數)經過p因式化了(其餘這樣的函數):

q = U h . p

若是你把p看做選取m的生成元;q看做在n中選擇「一樣的」生成元;而後你就能把h看做兩個幺半羣的生成元間的映射了。記住,由定義,h能夠保持幺半羣的結構。這就意味着一個幺半羣的兩個生成元的積會映射到第二個幺半羣的兩個對應的生成元的積,以此類推。

monoid-ranking

這種排名方式就能用來找到最好的那個候選者——自由幺半羣了。這兒是定義:

咱們說 m(連同函數 p)是生成元爲 x的自由幺半羣當且僅當有 惟一的m到其餘幺半羣 n(連同函數 q)的知足上述因式分解性質的態射 h
(容我再自做多情地提醒一下,全部用泛構造方式所作的定義中的惟一均是指在同構的意義下惟一,這裏也不例外,譯者注。)

剛好,這就能夠回答咱們的第二個問題。函數U h就能夠把U m的多個對象坍縮成U n的一個對象。這個坍縮對應了在自由幺半羣中對更多的元素進行指定的過程。所以,任意的由生成元x獲得的幺半羣均可以經過對x上自由幺半羣進行一些指定來獲得。而自由幺半羣就是僅進行最小數目的指定而獲得的那個。

咱們在講到伴隨時還會遇到自由幺半羣。

挑戰

  1. 你可能會以爲(就像我最初那樣)幺半羣同態要保持單位元的條件是多餘的。畢竟,咱們知道 對於全部的a

    h a * h e = h (a * e) = h a

    因此h e就是一個右結合的單位元(相似地,左結合的單位元)。問題在於對全部的ah a可能只能取到靶幺半羣的一個子羣。這樣在h的像以外就可能有個「真正」的單位元。 請證實兩個幺半羣之間保持乘法的態射必須自動地保持單位元。

  2. 考慮一個從帶有列表鏈接操做的整數列表到帶有乘法的整數的幺半羣同態。空列表[]的像是什麼?假定全部的單元素列表被映射爲他們中的那個整數,就是說[3]映爲3,等等。[1, 2, 3, 4]的像是什麼?有多少個不一樣的列表映爲整數12?這兩個幺半羣之間是否還有別的同態?
  3. 單例集生成的自由幺半羣是什麼?你能不能把它當作什麼東西的同構?

致謝

感謝Gershom Bazerman檢查個人數學和邏輯,以及André van Meulebrouck在整個系列中的編輯上的幫助。

下一篇:可表函子

相關文章
相關標籤/搜索