什麼是free structure?
在Data type a la carte中,我看到了這句話:
「In general, a structure is called free when it is left-adjoint to a forgetful functor.」left adjoint完全不明白,是什麼?forgetful functor明白了一點,但是wikipedia, mathworld, nlab上都沒看到足夠的例子。。。有人能舉幾個例子嗎?另外順帶球個faithful functor的例子
溫馨提示:為確保閱讀體驗請在電腦上用瀏覽器閱讀。
基本更新完成,歡迎@霧雨魔理沙@閱千人而惜知己@祖與占@彭飛 評論。謝邀,Free Structure是一個牽扯很多基礎概念的東西,先簡單的說一下吧。Free是什麼,用人話來說就是自由自在,自然而然。再具體一點就是:Free Structure就是依其自性自由自在的構造了一個自然而然呈現的結構。Free Structure是由較簡單的類型通過簡單而自然的方法構造得到的,具體如下:
1. Free Structure擁有類型F,其基於的基底類型是X,還有額外的Free Structure的運算。2. 定義一個嵌入函數ins: X -&> F,該函數將類型X的值通過簡單而自然的方法變為(injection)類型F的值。3. Free Structure的類型F只包含由嵌入函數ins得到的值,和由這些值通過Free Structure的運算得到的值。既沒有多餘的值,也沒有少必要的值,恰到好處。4. Free Structure的運算規則適用於類型F的所有這些值,類型F包含的所有值滿足Free Structure的定義和運算規則。我們可以將Free看成一個類型構造,其將類型X構造成Free Structure的類型F,類型X的值的集合是該Free Structure的生成集。下面這張圖解釋了Free的構造過程。以Monoid為例,類型F和類型G都是基於類型X的Monoid,其中類型F是Free Structure,一般也稱為FreeMonoid,是基於類型X的所有Monoid中最好的一個候選,是所有基於類型X的Monoid組成的範疇Mon的初始對象(initial object)。所有其它的Monoid都可以從FreeMonoid得到,都有一個唯一的從FreeMonoid到其它Monoid的同態態射(monoid homomorphism),FreeMonoid在同構上來說是唯一的。也就是說,我們有一個ins的函數,類型X到類型F的一個注入函數,如果對任一個從類型X到G的函數f,則有唯一的函數free f,可以從類型F得到類型G。函數free f也可稱為求值函數,將類型F的數據結構求值為類型G的值。在Haskell的List中,free就是我們熟悉的fold,List就是FreeMonoid(在有限元素的情況下)。
class Monoid m where
empty :: m
mappend :: m -&> m -&> m
data [x] = [] | x : [x] -- this is pseudo code
instance Monoid [x] where
mempty = []
mappend = (++)
ins :: x -&> [x]
ins x = [x]
free f :: Monoid b =&> (x -&> b) -&> [x] -&> b
-- free f = foldr (x b -&> f x `mappend` b) mempty
free f [] = mempty
free f (x:xs) = f x `mappend` free f xs
class Applicative m =&> Monad m where
return :: a -&> m a
join :: m (m a) -&> m a
data Free f a = Pure a | Free (f (Free f a))
instance Functor f =&> Monad (Free f) where
return = Pure
join (Pure a) = a
join (Free fa) = Free (fmap join fa)
ins :: (Functor f) =&> f a -&> Free f a
ins fa = Free (fmap Pure fa)
free :: (Functor f, Monad g) =&>
(forall a. f a -&> g a) -&> (forall a. Free f a -&> g a)
free f (Pure a) = return a
free f (Free fa) = join (f (fmap (free f) fa))
FreeApplicative是Applicative的Free Structure,是所有Applicative組成的範疇的初始對象(initial object),FreeApplicative將任意自函子f變為Applicative,自函子f是FreeApplicative的生成集。當我們的DSL語言的元語不需要上下文相關時,使用FreeApplicative就可以了,性能會更高。同樣的,Applicative也是自函子範疇上的Monoid,只是自函子的張量積和Monad的不同。因此FreeApplicative和FreeMonoid也有類似的結構,可以按如下方式定義FreeApplicative。
class Functor f =&> Applicative f where
pure :: a -&> f a
(&<*&>) :: f (a -&> b) -&> f a -&> f b
-- define this for express monoid of endofunctor
class Functor f =&> Monoidal f where
unit :: f ()
(**) :: f a -&> f b -&> f (a, b)
infixr 4 :$:
data FreeA f a = Pure a | forall b. f (b -&> a) :$: FreeA f b
instance Functor f =&> Applicative (FreeA f) where
return = Pure
Pure g &<*&> y = fmap g y
(h :$: as) &<*&> y = fmap uncurry h :$: ((,) &<$&> as &<*&> y)
ins :: (Functor f) =&> f a -&> FreeA f a
ins fa = fmap const fa :$: Pure ()
free :: (Functor f, Applicative g) =&>
(forall a. f a -&> g a) -&> (forall a. FreeA f a -&> g a)
free f (Pure a) = pure a
free f (h :$: as) = f h &<*&> free f as
從上面FreeMonoid、FreeApplicative和FreeMonad這三個例子我們可以看到,其實現有很高的相似性,這是因為這三種數據類型都具有Monoid這個結構,只是基底類型和單位元、乘法不一樣,因此具有同樣的形式 μX . I + A ? X。也即這三種數據類型是函子I +A ? ?的不動點,其具有類似的形式,我們再看一下這三種數據類型的定義,其形式很具有一致性。
X = I + A ? X
data [x] = [] | x : [x]
data FreeA f a = Pure a | forall b. f (b -&> a) :$: FreeA f b
data Free f a = Pure a | Free (f (Free f a))
遺忘函子(forgetful functor)和Free相反,其將Free Structure的類型F變換為其基底類型X。簡單的例子就是F-Alg範疇中的forgetful functor其形式為U ∶ F-Alg(C) → C,其作用是將F-Alg中額外的信息都遺忘掉,只剩下範疇C中的信息,定義為U ?A, a? = A 和U h = h,這裡 ?A, a? 是F-Alg(C)的對象。Free和遺忘函子U組成一對伴隨函子,Free是左伴隨,U是右伴隨,記為Free -| U。因此我們有Hom_F-Alg(Free A, B) ? HomC(A, U B),Free和U的伴隨關係如下圖所示。
伴隨(adjunction)是範疇論中的一個基本而又重要的概念,幾乎所有的數學對象都可以由伴隨來得到。伴隨包括伴隨函子(adjoint functor)和伴隨函數(adjunction function),這是一對互相反著運動的相生相伴的系統。下面這張伴隨圖簡明扼要的描述了伴隨的關係。那麼伴隨究竟是什麼呢,讓我們緩緩道來。當我們有兩個函子F : D -&> C和G : C -&> D,如果如下的條件成立,則我們就說F和G是一對伴隨函子,並稱F是G的左伴隨函子。
phiL: HomC(F d, c) ? HomD(d, G c) :phiR
ε : F ° G -&> Id
η : Id -&> G ° F
上面的phiL和phiR是一對自然同構,phiL將HomC(F d, c)中的函數變為HomD(d, G c)中的函數,phiR則相反。f和g是一對伴隨函數,f是左伴隨函數,g是右伴隨函數。η和ε是一對自然變換,η是所有函數g的unit,ε是所有函數f的counit。可以看到,伴隨中的一切都是一陰一陽,相生相伴,陰陽相互變化的。
那麼伴隨中的陰陽是如何變化的呢,其符合如下這些規律:phiL f = g === f = phiR g
f = ε ° phiR g
g = phiL f ° η
f = ε . phiR (phiL f)
g = phiL (phiR g) . η
phiL id = η
phiR id = ε
id = εF ° Fη --- F --Fη--&> F°G°F --εF--&> F
id = Gε ° ηG --- G --ηG--&> G°F°G --Gε--&> G
class (Functor f, Functor g) =&> Adjoint f g where
counit :: (f (g a)) -&> a
unit :: a -&> (g (f a))
phiL :: (Adjoint f g) =&> (f a -&> b) -&> (a -&> g b)
phiL f = fmap f . unit
phiR :: (Adjoint f g) =&> (a -&> g b) -&> (f a -&> b)
phiR f = counit . fmap f
instance Adjoint ((,) a) ((-&>) a) where
-- counit :: (a, a -&> b) -&> b
counit (a, f) = f a
-- unit :: b -&> (a -&> (a, b))
unit b = a -&> (a, b)
眼尖的同學可能會發現上面的unit函數返回了一個類似State s的數據類型,如果我們按如下方式定義StateA,則可以得到一個StateA s的Monad。
-- Compose ((-&>) s) ((,) s)
newtype StateA s a = StateA { runStateA :: s -&> (s, a) }
instance Monad (StateA s) where
return a = StateA $ s -&> (s, a) --- unit b = a -&> (a, b)
join (StateA st) = StateA $ s -&> let (s", t) = st s in t s"
上面的StateA的s -&> (s, a)可以看成是函子((-&>) s)和((,) s)的組合,即Compose ((-&>) s) ((,) s)。更一般化的,若我們有F和G兩個伴隨函子,其中F是左伴隨函子,則通過函子的組合我們可以得到一個Monad,即Compose G F是一個Monad,具體如下所示:
newtype Compose f g a = Compose { getCompose :: f (g a) }
-- f is left adjoint functor of g
instance Adjoint f g =&> Monad (Compose g f) where
return a = Compose $ unit a
join m = Compose . fmap counit . getCompose $ fmap getCompose m
-- curry: Hom((a, b), c) = Hom(a, c^b) :uncurry
curry :: ((a, b) -&> c) -&> a -&> b -&> c
uncurry :: (a -&> b -&> c) -&> (a, b) -&> c
-- Compose ((-&>) s) (, s)
newtype State s a = State { runState :: s -&> (a, s) }
-- Adjoint (, s) ((-&>) s)
-- phiL id = curry id = η
-- phiR id = uncurry id = ε
unit = (,) = curry id = coeval :: a -&> b -&> (a, b)
counit = uncurry ($) = uncurry id = eval :: (b -&> a, b) -&> a
instance Monad (State s) where
return a = State $ s -&> (a, s) --- unit a = -&> (a, b)
join (State st) = State $ s -&> let (t, s") = st s in t s"
可以看到State和StateA這兩個數據類型非常相似,其區別就在於(a, s)和(s, a)這個交換。實際上在Haskell的類型系統中(a, s)和(s, a)是同構的,因此State和StateA是同構的。
我們很熟悉的兩種數據類型Product和Coproduct,也可以用伴隨函子來表示,而且很好的呈現了Product和Coproduct的對偶關係。在Haskell中Product a b類型就是(a, b),Coproduct a b類型就是Either a b。我們再引入? ∶ C → C × C這個Diagonal Functor,其定義為?A = ?A, A? 和?f = ?f ,f ?。那麼Either和(,)這兩個Bifunctor和Δ 這個Diagonal Functor就一起組成了伴隨三角,表示為Either ? Δ ? (,),使得類型(a, b)和類型Either a b互相對偶。將Either記為+和(,)記為x,則如下圖所示。
因Haskell的類型系統中沒有product kind,無法表示乘積範疇 C × C,故上圖無法用Haskell的代碼來表示,大家只好腦補了。最後,我們來看看最重要的米田引理和伴隨函子之間的關係。米田引理的定義如下:
上面的米田引理定義誘導出了一對伴隨函子(adjoint functor) ,左伴隨函子(A ? ?) 和右伴隨函子Hom(A, ?),從而如下的同構形式成立:Hom(Cop?C, Set)?Hom(C, Hom(Cop, Set))更具體的描述請看米田引理的在編程中的實際應用? - parker liu 的回答 。
fully faithful的函子F引導的如下函數Fx,y是一個雙射函數,誘導出一個嵌入關係。
一個重要的例子就是米田嵌入函子Y,該函子將任意一個local small category範疇C嵌入到範疇Fun(Cop, Set)。我們再次應用米田嵌入,可以得到高階函子範疇Fun(Fun(Cop, Set), Set),多次應用,則可以得到更高階到函子範疇。伴隨函子描述了一個事物的兩個方面,即一陰一陽。這兩個方面的變化是相互關聯又互相反向運動的,很像太極圖中的陰陽變化之道。
在編程實踐方面,我們往往會遇到靈活和高效這對矛盾,即能夠靈活組合的程序往往是低效運行的,而高效運行的程序往往又是難以組合的。如何解決這對矛盾呢,伴隨函子給了我們一個可能的方向,我們可以在一個範疇中實現可以靈活組合的形式,另一個範疇中實現高效運行的形式,利用伴隨函子來將靈活組合的形式轉換為高效運行的形式。具體如何做呢,米田引理和丘奇表示(Church representation)給了我們一些啟示。參考鏈接:Free structureFree MonoidsDefinition Let A and B be categories. If F : A → B and U : B
→ A are functors, we say that F is left adjoint to U and U is right
adjoint to F provided there is a natural transformation η : id → UF suchthat for any objects A of A and B of B and any arrow f : A → UB, thereis a unique arrow g : FA → B such thatcommutes.記為F ? U (F為U的左伴隨, U為F的右伴隨, UF是 U? F的縮寫)Free Monoid就是free structure的例子
恆等函子 是 faithful functor的例子 (逃我只是個搬運工
Ref: http://www.math.mcgill.ca/triples/Barr-Wells-ctcs.pdf--------------------------------------在研究monad和comand的關係時,看過adjoint伴隨可視為isomorphism between arrows,把? 記為Adjunctiontrait Adjunction[F[_],G[_]] { //F is left adjoint to G
def left[A,B](f: F[A] =&> B): A =&> G[B]
def right[A,B](f: A =&> G[B]): F[A] =&> B
}
Composing adjoint functors 可以形成 monad和comonad
我從free algebra的角度來答一下吧,
free monad只是free algebra中的一種,還有很多free algebra的例子,
例如,free monoid,free group,free ring等等。
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
free algebra與forgetful functor和left adjoint有關:
For each type of algebras, we have the category of all algebras of the given type, the forgetful functor , and its left adjoint , which assigns to each set the free algebra of type generated by elements of .
——《Categories for the Working Mathematician 2nd - P137》
我們看到,一個有結構的範疇,通過forgetful functor損失了一些結構,映射成了另外一個範疇 。一個直觀的想法就是,我們能否把 再映射回來 。
這不太容易,因為forgetful functor已經損失了一些結構。但是我們可以通過類似「求極值」的方式,找到一個最簡復原方式。那就是通過forgetful functor的left adjoint來完成,因為forgetful functor的left adjoint剛好是一個從 到 的函子。
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1. 什麼是類型為 的代數
在universal algebra中,一個algebra由一個集合 以及集合上的一系列運算構成。
集合 上的 元運算是一個函數,它將 中的 個元素,映射為一個元素,
代數中所有運算的集合記為 ,我們稱該代數是一個 類型的代數。
所有類型為 的代數,構成了一個範疇 ,
它的對象為某一個類型為 的代數,箭頭為代數之間的代數同態。
2. 什麼是forgetful functor
一個函子可能會「遺忘」範疇中的部分(或全部)結構,這樣的函子稱為forgetful functor。
例如,forgetful functor ,將範疇 中的每一個群 ,映射為一個由群 的所有元素組成的集合 ,(「遺忘」了建立在群乘法之上的群結構,)並且將範疇 中的任意兩個群之間的群同態,映射為兩個集合之間的函數。
3. 什麼是left adjoint
要理解left adjoint的概念比較麻煩,下面我們要分以下幾個概念來分別介紹,
comma category,coslice category,initial object,initial morphism,adjoint functor。
3.1 comma category
給定範疇 和函子 ,
我們構造comma category,記為 ,它由以下對象和箭頭組成:
範疇的對象為三元組 ,其中, 是範疇 中的對象,d是範疇 中的對象, 是範疇 中的箭頭。
範疇的箭頭為二元組 ,其中, , ,並且滿足, 。
3.2 coslice category
給定範疇 和函子 ,
取 中的某個元素 ,它唯一對應一個函子 ,
在這種情況下comma category ,就可以記為 ,稱為coslice category。
coslice category 的對象是 ,其中, 是 中的對象, 是 中的箭頭。
coslice category 的箭頭是 ,其中 ,並且滿足, 。
3.3 initial object
設 是一個範疇, 是它的一個對象,如果對於 中的任意對象 ,存在唯一的箭頭 ,就稱 是範疇 的initial object。
3.4 initial morphism
設 是範疇, 是函子, 是範疇 中的一個對象,
根據initial object的定義,coslice category 的initial object 滿足以下條件,
對於coslice category 中的任意對象 ,存在唯一的箭頭,,使得 。
這個initial object ,稱為從對象 到函子 的initial morphism。
(注意,這裡是從對象到函子,沒寫錯,指的是coslice category 。)
3.5 adjoint functor
設 是範疇, 是函子, 是範疇 中的對象,
是從對象 到函子 的initial morphism,其中 。
是從對象 到函子 的initial morphism,其中 。
根據initial morphism的性質,對於 中的箭頭 ,存在 中唯一的箭頭 ,使得 。
因此,我們找到了一個從範疇 到 的對應關係。
我們把範疇 中的對象 ,分別對應到了範疇 的對象 上,
把範疇 中的箭頭 ,對應到了範疇 的箭頭 上。
如果對於範疇 中任意的對象和箭頭,都能滿足這個條件,
我們就找到了一個從範疇 到範疇 的函子, ,
稱為 的left adjoint, 稱為 的right adjoint,記為 。
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
以上我們介紹了範疇 ,forgetful functor和left adjoint,現在我們就可以理解free algebra的概念了。
free algebra,就是forgetful functor 的left adjoint ,作用在範疇 的對象 上之後,得到的一個類型為 的代數 。
其中 稱為代數 的生成集(generator), 稱為由 生成的代數。
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
4. 我們補充一下free monoid的概念(2017.07.09)
4.1 Kleene closure
集合 的Kleene closure定義如下,
其中, , , ,
中的元素稱為string, 定義中的 將兩個string 和 連接到了一起,稱為string concatenation,不妨記為「 」。
4.2 free monoid
可以證明, 連同string concatenation運算,是一個由 生成的free monoid ,
即證明 是coslice category 的initial object,其中 。
Why is the free monoid free?
4.3 generator
其實剛才的描述不太嚴謹,因為free algebra還與forgetful functor的定義有關,
我們還需補充以下定義,定義forgetful functor為 , 是所有monoid構成的範疇, 是所有集合構成的範疇。forgetful functor將 中一個具體的monoid ,映射為它的群元素之集合 ,將該monoid與其他monoid之間的群同態,映射為集合之間的函數。
因此,forgetful functor 將monoid 映射為集合 ,它left adjoint ,將 映射為由 生成的free monoid 。
注意,forgetful functor將 映射為 ,而不是 ,free monoid 是由 生成的,而不是 。
設 , 是任意的一個monoid,則映射 ,確定了唯一的群同態 ,使得 ,因此, 是從 到 的initial morphism, 是由 生成的free monoid。
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
參考:
1. Categories for the Working Mathematician 2nd
2. Category theory for computer science
3. A Course in Universal Algebra
4. Wikipedia: Universal Algebra
5. Wikipedia: Forgetful functor
6. Wikipedia: Initial and terminal objects
7. Wikipedia: Comma Category
8. Wikipedia: Universal Property
9. Wikipedia: Adjoint Functor
10. Wikipedia: Free Object
11. Wikipedia: Free Algebra
12. Stack Exchange: Why is the free monoid free
forgetful functor 是可遺函子吧。。。(翻出範疇論筆記)這種感覺。。。伴隨函子就不是很清楚了。。。我去問問老師(
首先,所有 set 的範疇是 Set,所有 monoid 的範疇是 Mon。顯然每個 monoid 都有一個 underlying set,這個「脫」的過程可以看作一個 forgetful functor,叫 U : Mon -&> Set。List 這個結構可以從一個 set 構建一個 monoid,免費穿上了 monodic structure,可以看作另一個 functor,List : Set -&> Mon。這兩個 functor 顯然是對稱的,那他們是不是互為 left/right adjoint 呢?
如果是,需要有這麼一個 natural isomorphism:對任意 s in Set 和任意 m in Mon,List s -&> m ? s -&> U m。left/right adjoint 指示 functor 出現在左側還是右側。
哎~如果寫成 adjunction 的另一種表示方式 unit η 和 counit ε :η : Id -&> U ° Listε : List ° U -&> Id其中 Id 為 identity functor。可見 U 和 List 的互為 inverse 關係。推薦閱讀:
※如何理清 lens 這個庫的各個組件,熟悉各種高級玩法?
※為什麼函數式語言中all odd [] 得到True?
※C++ 用作函數式語言時,是否有語法上的缺失?
※怎樣評價 LambdaConf 提出的「函數式編程技能表」?
※Haskell Book 這本書怎麼樣?