[英]Are codatatypes really terminal algebras?
(免責聲明:我不是 100% 確定 codatatype 是如何工作的,尤其是在不涉及終端代數時)。
考慮“類型的類別”,類似於Hask ,但可以進行任何適合討論的調整。 在這樣一個類別中,據說(1)初始代數定義數據類型,(2)終端代數定義余數據類型。
我正在努力說服自己相信(2)。
考慮函子T(t) = 1 + a * t
。 我同意最初的T
代數是明確定義的,並且確實定義了[a]
,即a
的列表。 根據定義,初始T
代數是類型X
和 function f:: 1+a*X -> X
,因此對於任何其他類型Y
和 function g:: 1+a*Y -> Y
,有正好是一個 function m:: X -> Y
使得m. f = g. T(m)
m. f = g. T(m)
m. f = g. T(m)
(其中.
表示在 Haskell 中的 function 組合運算符)。 With f
interpreted as the list constructor(s), g
the initial value and the step function, and T(m)
the recursion operation, the equation essentially asserts the unique existance of the function m
given any initial value and any step function defined in g
,這需要一個行為良好的基礎fold
以及基礎類型,即a
的列表。
例如, g:: Unit + (a, Nat) -> Nat
可以是() -> 0 | (_,n) -> n+1
() -> 0 | (_,n) -> n+1
,在這種情況下m
定義長度 function,或者g
可以是() -> 0 | (_,n) -> 0
() -> 0 | (_,n) -> 0
,然后m
定義一個常數零 function。 這里的一個重要事實是,對於任何g
, m
始終可以唯一定義,就像fold
不會對其 arguments 施加任何約束,並且始終會產生唯一的明確定義的結果。
這似乎不適用於終端代數。
考慮上面定義的相同的仿函數T
終端T
代數的定義與初始代數相同,不同之處在於m
現在是X -> Y
類型,方程現在變為m. g = f. T(m)
m. g = f. T(m)
m. g = f. T(m)
。 據說這應該定義一個潛在的無限列表。
我同意這有時是真的。 例如,當g:: Unit + (Unit, Int) -> Int
定義為() -> 0 | (_,n) -> n+1
() -> 0 | (_,n) -> n+1
像以前一樣,然后m
的行為使得m(0) = ()
和m(n+1) = Cons () m(n)
。 對於非負n
, m(n)
應該是一個有限的單元列表。 對於任何負數n
, m(n)
應該是無限長的。 可以驗證上面的等式對於這樣的g
和m
成立。
但是,對於以下兩個修改后的g
定義中的任何一個,我再也看不到任何定義明確的m
了。
首先,當g
再次為() -> 0 | (_,n) -> n+1
() -> 0 | (_,n) -> n+1
但屬於g:: Unit + (Bool, Int) -> Int
類型, m
必須滿足m(g((b,i))) = Cons bm(g(i))
,這意味着結果取決於b
。 但這是不可能的,因為m(g((b,i)))
實際上只是m(i+1)
沒有提到b
,所以方程沒有明確定義。
其次,當g
再次是g:: Unit + (Unit, Int) -> Int
類型但被定義為常數零 function g _ = 0
時, m
必須滿足m(g(())) = Nil
和m(g(((),i))) = Cons () m(g(i))
,這是矛盾的,因為它們的左側是相同的,都是m(0)
,而右側永遠不是相同的。
總之,有T
-代數沒有態射到假設的終端T
-代數中,這意味着終端T
-代數不存在。 如果有的話,codatatype Stream(或無限列表)的理論建模不能基於函子T(t) = 1 + a * t
的不存在終端代數。
非常感謝上面故事中任何缺陷的暗示。
(2) 終結代數定義了余數據類型。
這是不對的, codatatypes 是終端colgebras 。 對於您的T
函子,余代數是x
和f:: x -> T x
的類型。 (x1, f1)
和(x2, f2)
之間的T
-coalgebra 態射是g:: x1 -> x2
使得fmap g. f1 = f2. g
fmap g. f1 = f2. g
fmap g. f1 = f2. g
。 使用這個定義,終端T
-代數定義了可能的無限列表(所謂的“colists”),並且終端性由unfold
function 見證:
unfold :: (x -> Unit + (a, x)) -> x -> Colist a
請注意,盡管確實存在終端T
代數:它只是Unit
類型以及常數 function T Unit -> Unit
(這可以作為任何T
的終端代數)。 但這對於編寫程序並不是很有趣。
據說(1)初始代數定義數據類型,(2)終端代數定義余數據類型。
關於第二點,實際上據說終端余代數定義了余數據類型。
數據類型t
由其構造函數和折疊定義。
F t -> t
來建模(例如,Peano 構造函數O: nat
S: Nat -> Nat
被收集為單個 function in: Unit + Nat -> Nat
)。fold f: t -> x
對於任何代數f: F x -> x
(對於 nats, fold: ((Unit + x) -> x) -> Nat -> x
)。 codatatype t
由它的析構函數和展開定義。
t -> F t
(for example, streams have two destructors head: Stream a -> a
and tail: Stream a -> Stream a
, and they are collected as a single function out: Stream a -> a * Stream a
)。unfold f: x -> t
對於任何余代數f: x -> F x
(對於流, unfold: (x -> a * x) -> x -> Stream a
)。(免責聲明:我不是 100% 確定 codatatype 是如何工作的,尤其是在不涉及終端代數時)。
余數據類型或協導數據類型只是由它的消除而不是它的引入來定義的。
似乎有時使用終端代數(非常令人困惑)來指代最終的 colgebra ,這實際上定義了余數據類型。
考慮上面定義的相同的仿函數 T。 終端 T 代數的定義與初始代數相同,不同之處在於 m 現在是 X -> Y 類型,方程現在變為 m。 g = f。 Tm值)。 據說這應該定義一個潛在的無限列表。
所以我認為這是你出錯的地方:“ m ∘ g = f ∘ T ( m )”應該顛倒過來,改為“ T ( m ) ∘ f = g ∘ m ”。 That is, the final coalgebra is defined by a carrier set S and a map g : S → T ( S ) such that for any other coalgebra ( R , f : R → T ( R )) there is a unique map m : R → S使得T ( m ) ∘ f = g ∘ m 。
m由 map 遞歸地唯一定義,當f映射到Left ()
) 時返回Left ()
,當f映射到 Right (x, xs) 時返回Right (x, m xs)
Right (x, xs)
,即它是將余代數分配給其唯一態射到最終的余代數,並表示這種類型的獨特變形/展開,這應該很容易說服自己實際上是一個可能為空且可能無限的 stream。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.