“編程代碼”在編程環境中意味着什麼?

本文翻譯自:What does “coalgebra” mean in the context of programming?

I have heard the term "coalgebras" several times in functional programming and PLT circles, especially when the discussion is about objects, comonads, lenses, and such. 我在函數式編程和PLT圈子中多次聽到過“enggebras”這個術語,特別是在討論對象,comonads,鏡頭等時。 Googling this term gives pages that give mathematical description of these structures which is pretty much incomprehensible to me. 谷歌搜索這個術語給出了對這些結構進行數學描述的頁面,這對我來說幾乎是不可理解的。 Can anyone please explain what coalgebras mean in the context of programming, what is their significance, and how they relate to objects and comonads? 任何人都可以解釋一下代數在編程環境中的意義,它們的意義是什麼,以及它們與對象和共同體的關係?


#1樓

參考:https://stackoom.com/question/15CEm/編程代碼-在編程環境中意味着什麼


#2樓

Going through the tutorial paper A tutorial on (co)algebras and (co)induction should give you some insight about co-algebra in computer science. 閱讀教程論文關於(共)代數和(共)歸納的教程應該會給你一些關於計算機科學中的共同代數的見解。

Below is a citation of it to convince you, 以下是引用你的引用,

In general terms, a program in some programming language manipulates data. 一般而言,某些編程語言中的程序操縱數據。 During the development of computer science over the past few decades it became clear that an abstract description of these data is desirable, for example to ensure that one's program does not depend on the particular representation of the data on which it operates. 在過去幾十年的計算機科學發展過程中,很明顯需要對這些數據進行抽象描述,例如確保一個人的程序不依賴於其運行的數據的特定表示。 Also, such abstractness facilitates correctness proofs. 而且,這種抽象性有助於正確性證明。
This desire led to the use of algebraic methods in computer science, in a branch called algebraic specification or abstract data type theory. 這種願望導致在計算機科學中使用代數方法,在稱爲代數規範或抽象數據類型理論的分支中。 The object of study are data types in themselves, using notions of techniques which are familiar from algebra. 研究對象本身就是數據類型,使用了代數中熟悉的技術概念。 The data types used by computer scientists are often generated from a given collection of (constructor) operations,and it is for this reason that "initiality" of algebras plays such an important role. 計算機科學家使用的數據類型通常是從​​給定的(構造函數)操作集合生成的,正是由於這個原因,代數的“初始性”起着如此重要的作用。
Standard algebraic techniques have proved useful in capturing various essential aspects of data structures used in computer science. 事實證明,標準代數技術可用於捕獲計算機科學中使用的數據結構的各種基本方面。 But it turned out to be difficult to algebraically describe some of the inherently dynamical structures occurring in computing. 但事實證明,很難用代數方式描述計算中發生的一些固有的動態結構。 Such structures usually involve a notion of state, which can be transformed in various ways. 這種結構通常涉及國家概念,可以以各種方式進行轉換。 Formal approaches to such state-based dynamical systems generally make use of automata or transition systems, as classical early references. 這種基於狀態的動態系統的形式化方法通常使用自動機或過渡系統,作爲經典的早期參考。
During the last decade the insight gradually grew that such state-based systems should not be described as algebras, but as so-called co-algebras. 在過去的十年中,人們逐漸認識到,這種基於狀態的系統不應該被描述爲代數,而應該被稱爲代數代數。 These are the formal dual of algebras, in a way which will be made precise in this tutorial. 這些是代數的正式對偶,在本教程中將以精確的方式進行。 The dual property of "initiality" for algebras, namely finality turned out to be crucial for such co-algebras. 代數的“初始性”的雙重性質,即終結性對於這種共代數來說是至關重要的。 And the logical reasoning principle that is needed for such final co-algebras is not induction but co-induction. 並且這種最終共代數所需的邏輯推理原理不是歸納,而是共同歸納。


Prelude, about Category theory. 前奏,關於範疇理論。 Category theory should be rename theory of functors. 類別理論應該重命名仿函數理論。 As categories are what one must define in order to define functors. 因爲類別是定義仿函數必須定義的類別。 (Moreover, functors are what one must define in order to define natural transformations.) (此外,仿函數是人們必須定義的,以便定義自然變換。)

What's a functor? 什麼是算子? It's a transformation from one set to another which preserving their structure. 它是從一組到另一組的轉換,保留了它們的結構。 (For more detail there is a lot of good description on the net). (有關詳細信息,網上有很多很好的描述)。

What's is an F-algebra? 什麼是F代數? It's the algebra of functor. 它是仿函數的代數。 It's just the study of the universal propriety of functor. 這只是對仿函數普遍適用性的研究。

How can it be link to computer science ? 它如何與計算機科學聯繫起來? Program can be view as a structured set of information. 程序可以作爲一組結構化信息進行查看。 Program's execution correspond to modification of this structured set of information. 程序的執行對應於該結構化信息集的修改。 It sound good that execution should preserve the program structure. 執行應保留程序結構聽起來不錯。 Then execution can be view as the application of a functor over this set of information. 然後可以將執行視爲這組信息的仿函數應用程序。 (The one defining the program). (定義程序的那個)。

Why F-co-algebra ? 爲什麼F-co-algebra? Program are dual by essence as they are describe by information and they act on it. 程序是本質上是雙重的,因爲它們是通過信息來描述的,並且它們依賴於它。 Then mainly the information which compose program and make them changed can be view in two way. 那麼主要是組成程序並使它們改變的信息可以以兩種方式查看。

  • Data which can be define as the information being processed by the program. 可以定義爲程序正在處理的信息的數據。
  • State which can be define as the information being shared by the program. 可以定義爲程序共享信息的狀態。

Then at this stage, I'd like to say that, 那麼在這個階段,我想說,

  • F-algebra is the study of functorial transformation acting over Data's Universe (as been defined here). F代數是對數據宇宙上的函數變換的研究(如這裏定義的)。
  • F-co-algebras is the study of functorial transformation acting on State's Universe (as been defined here). F-co-algebras是研究狀態宇宙上的函數變換(如這裏定義的)。

During the life of a program, data and state co-exist, and they complete each other. 在程序的生命週期中,數據和狀態共存,並且它們彼此完成。 They are dual. 他們是雙重的。


#3樓

Algebras 代數

I think the place to start would be to understand the idea of an algebra . 我認爲開始的地方是理解代數的概念。 This is just a generalization of algebraic structures like groups, rings, monoids and so on. 這只是代數結構的推廣,如羣,環,幺半羣等。 Most of the time, these things are introduced in terms of sets, but since we're among friends, I'll talk about Haskell types instead. 大多數時候,這些東西是以集合的形式引入的,但由於我們是朋友之間,我將討論Haskell類型。 (I can't resist using some Greek letters though—they make everything look cooler!) (我無法抗拒使用一些希臘字母 - 它們讓一切看起來都更酷!)

An algebra, then, is just a type τ with some functions and identities. 因此,代數只是具有一些函數和身份的類型τ These functions take differing numbers of arguments of type τ and produce a τ : uncurried, they all look like (τ, τ,…, τ) → τ . 這些函數採用不同數量的τ類型的參數併產生τ :uncurried,它們看起來都像(τ, τ,…, τ) → τ They can also have "identities"—elements of τ that have special behavior with some of the functions. 它們也可以具有“身份” - τ元素,它們具有某些功能的特殊行爲。

The simplest example of this is the monoid. 最簡單的例子就是幺半羣。 A monoid is any type τ with a function mappend ∷ (τ, τ) → τ and an identity mzero ∷ τ . 幺半羣是任何類型τ ,具有函數mappend ∷ (τ, τ) → τ和同一性mzero ∷ τ Other examples include things like groups (which are just like monoids except with an extra invert ∷ τ → τ function), rings, lattices and so on. 其他例子包括諸如組之類的東西(除了具有額外的invert ∷ τ → τ函數之外,它們就像幺半羣一樣),環,格子等。

All the functions operate on τ but can have different arities. 所有功能都在τ運行,但可以有不同的特性。 We can write these out as τⁿ → τ , where τⁿ maps to a tuple of n τ . 我們可以寫這些出來作爲τⁿ → τ ,其中τⁿ映射到的元組n τ This way, it makes sense to think of identities as τ⁰ → τ where τ⁰ is just the empty tuple () . 這樣,將身份視爲τ⁰ → τ是有意義的,其中τ⁰只是空元組() So we can actually simplify the idea of an algebra now: it's just some type with some number of functions on it. 所以我們現在實際上可以簡化代數的概念:它只是一些帶有一些函數的類型。

An algebra is just a common pattern in mathematics that's been "factored out", just like we do with code. 代數只是數學中常見的模式,已被“排除”,就像我們使用代碼一樣。 People noticed that a whole bunch of interesting things—the aforementioned monoids, groups, lattices and so on—all follow a similar pattern, so they abstracted it out. 人們注意到一大堆有趣的東西 - 前面提到的幺半羣,羣體,格子等都遵循類似的模式,因此他們將其抽象出來。 The advantage of doing this is the same as in programming: it creates reusable proofs and makes certain kinds of reasoning easier. 這樣做的好處與編程相同:它可以創建可重複使用的證據,並使某些推理更容易。

F-Algebras F-代數

However, we're not quite done with factoring. 但是,我們還沒有完成因子分解。 So far, we have a bunch of functions τⁿ → τ . 到目前爲止,我們有一堆函數τⁿ → τ We can actually do a neat trick to combine them all into one function. 我們實際上可以做一個巧妙的技巧,將它們全部合併到一個函數中。 In particular, let's look at monoids: we have mappend ∷ (τ, τ) → τ and mempty ∷ () → τ . 特別是,讓我們看看幺半羣:我們有mappend ∷ (τ, τ) → τmempty ∷ () → τ We can turn these into a single function using a sum type— Either . 我們可以使用類型A和把這些成一個單一的功能, Either It would look like this: 它看起來像這樣:

op ∷ Monoid τ ⇒ Either (τ, τ) () → τ
op (Left (a, b)) = mappend (a, b)
op (Right ())    = mempty

We can actually use this transformation repeatedly to combine all the τⁿ → τ functions into a single one, for any algebra. 對於任何代數,我們實際上可以反覆使用這個變換將所有 τⁿ → τ函數組合成一個函數。 (In fact, we can do this for any number of functions a → τ , b → τ and so on for any a, b,… .) (事實上​​,對於任何 a, b,… ,我們可以爲任意數量的函數a → τb → τ等執行此操作。)

This lets us talk about algebras as a type τ with a single function from some mess of Either s to a single τ . 這讓我們談論代數作爲一種τ從一些亂七八糟的單一功能Either s到一個單一的τ For monoids, this mess is: Either (τ, τ) () ; 對於幺半羣,這個混亂是: Either (τ, τ) () ; for groups (which have an extra τ → τ operation), it's: Either (Either (τ, τ) τ) () . 對於組(具有額外的τ → τ操作),它是: Either (Either (τ, τ) τ) () It's a different type for every different structure. 對於每種不同的結構,它都是不同的類型。 So what do all these types have in common? 那麼所有這些類型有什麼共同之處呢? The most obvious thing is that they are all just sums of products—algebraic data types. 最明顯的是它們都只是產品 - 代數數據類型的總和。 For example, for monoids, we could create a monoid argument type that works for any monoid τ: 例如,對於monoids,我們可以創建一個適用於任何 monoidτ的monoid參數類型:

data MonoidArgument τ = Mappend τ τ -- here τ τ is the same as (τ, τ)
                      | Mempty      -- here we can just leave the () out

We can do the same thing for groups and rings and lattices and all the other possible structures. 我們可以爲組,環和格子以及所有其他可能的結構做同樣的事情。

What else is special about all these types? 所有這些類型還有什麼特別之處? Well, they're all Functors ! 好吧,他們都是Functors Eg: 例如:

instance Functor MonoidArgument where
  fmap f (Mappend τ τ) = Mappend (f τ) (f τ)
  fmap f Mempty        = Mempty

So we can generalize our idea of an algebra even more. 因此,我們可以更廣泛地概括我們的代數概念。 It's just some type τ with a function f τ → τ for some functor f . 對於某些函子f它只是某種類型τ ,函數f τ → τ In fact, we could write this out as a typeclass: 事實上,我們可以把它寫成一個類型類:

class Functor f ⇒ Algebra f τ where
  op ∷ f τ → τ

This is often called an "F-algebra" because it's determined by the functor F . 這通常被稱爲“F代數”,因爲它由函子F確定。 If we could partially apply typeclasses, we could define something like class Monoid = Algebra MonoidArgument . 如果我們可以部分應用類型類,我們可以定義class Monoid = Algebra MonoidArgument

Coalgebras 餘代數

Now, hopefully you have a good grasp of what an algebra is and how it's just a generalization of normal algebraic structures. 現在,希望你能很好地掌握代數是什麼,以及它如何只是普通代數結構的推廣。 So what is an F-coalgebra? 什麼是F-coalgebra? Well, the co implies that it's the "dual" of an algebra—that is, we take an algebra and flip some arrows. 好吧,co意味着它是代數的“雙重” - 也就是說,我們採用代數並翻轉一些箭頭。 I only see one arrow in the above definition, so I'll just flip that: 我只在上面的定義中看到一個箭頭,所以我只是翻轉它:

class Functor f ⇒ CoAlgebra f τ where
  coop ∷ τ → f τ

And that's all it is! 這就是全部! Now, this conclusion may seem a little flippant (heh). 現在,這個結論可能看起來有點輕率(嘿)。 It tells you what a coalgebra is, but does not really give any insight on how it's useful or why we care. 它告訴你什麼是代數是什麼 ,但並沒有真正給出任何關於它如何有用或我們關心的原因的見解。 I'll get to that in a bit, once I find or come up with a good example or two :P. 一旦我找到或想出一個好的例子,我會稍微談談它:P。

Classes and Objects 類和對象

After reading around a bit, I think I have a good idea of how to use coalgebras to represent classes and objects. 在閱讀了一下之後,我想我很清楚如何使用代數來表示類和對象。 We have a type C that contains all the possible internal states of objects in the class; 我們有一個C ,它包含了類中對象的所有可能的內部狀態; the class itself is a coalgebra over C which specifies the methods and properties of the objects. 類本身是C上的代數,它指定了對象的方法和屬性。

As shown in the algebra example, if we have a bunch of functions like a → τ and b → τ for any a, b,… , we can combine them all into a single function using Either , a sum type. 如代數示例所示,如果我們有一堆函數,如a → τb → τ對於任何a, b,… ,我們可以使用Either (和類型)將它們全部組合成單個函數。 The dual "notion" would be combining a bunch of functions of type τ → a , τ → b and so on. 雙重“概念”將組合τ → aτ → b等類型的一系列函數。 We can do this using the dual of a sum type—a product type. 我們可以使用sum類型的對偶 - 產品類型來實現這一點。 So given the two functions above (called f and g ), we can create a single one like so: 所以考慮到上面的兩個函數(稱爲fg ),我們可以像這樣創建一個函數:

both ∷ τ → (a, b)
both x = (f x, g x)

The type (a, a) is a functor in the straightforward way, so it certainly fits with our notion of an F-coalgebra. 類型(a, a)是一種直接方式的仿函數,所以它肯定符合我們的F-餘代數的概念。 This particular trick lets us package up a bunch of different functions—or, for OOP, methods—into a single function of type τ → f τ . 這個特殊的技巧讓我們將一堆不同的函數 - 或者對於OOP,方法 - 打包成一個類型爲τ → f τ函數。

The elements of our type C represent the internal state of the object. 類型C的元素表示對象的內部狀態。 If the object has some readable properties, they have to be able to depend on the state. 如果對象具有一些可讀屬性,則它們必須能夠依賴於狀態。 The most obvious way to do this is to make them a function of C . 最明顯的方法是使它們成爲C的函數。 So if we want a length property (eg object.length ), we would have a function C → Int . 因此,如果我們想要一個長度屬性(例如object.length ),我們將有一個函數C → Int

We want methods that can take an argument and modify state. 我們想要可以採用參數和修改狀態的方法。 To do this, we need to take all the arguments and produce a new C . 爲此,我們需要獲取所有參數並生成一個新的C Let's imagine a setPosition method which takes an x and a y coordinate: object.setPosition(1, 2) . 讓我們設想一個採用xy座標的setPosition方法: object.setPosition(1, 2) It would look like this: C → ((Int, Int) → C) . 它看起來像這樣: C → ((Int, Int) → C)

The important pattern here is that the "methods" and "properties" of the object take the object itself as their first argument. 這裏重要的模式是對象的“方法”和“屬性”將對象本身作爲它們的第一個參數。 This is just like the self parameter in Python and like the implicit this of many other languages. 這就像self在Python參數和喜歡的隱性this許多其他語言的。 A coalgebra essentially just encapsulates the behavior of taking a self parameter: that's what the first C in C → FC is. 一個代數基本上只是封裝了一個self參數的行爲:這就是C → FC的第一個C

So let's put it all together. 所以我們把它們放在一起吧。 Let's imagine a class with a position property, a name property and setPosition function: 讓我們設想一個具有position屬性, name屬性和setPosition函數的類:

class C
  private
    x, y  : Int
    _name : String
  public
    name        : String
    position    : (Int, Int)
    setPosition : (Int, Int) → C

We need two parts to represent this class. 我們需要兩個部分來代表這個類。 First, we need to represent the internal state of the object; 首先,我們需要表示對象的內部狀態; in this case it just holds two Int s and a String . 在這種情況下,它只包含兩個Int和一個String (This is our type C .) Then we need to come up with the coalgebra representing the class. (這是我們的C型。)然後我們需要提出代表該類的代數。

data C = Obj { x, y  ∷ Int
             , _name ∷ String }

We have two properties to write. 我們有兩個屬性要寫。 They're pretty trivial: 它們非常簡單:

position ∷ C → (Int, Int)
position self = (x self, y self)

name ∷ C → String
name self = _name self

Now we just need to be able to update the position: 現在我們只需要能夠更新位置:

setPosition ∷ C → (Int, Int) → C
setPosition self (newX, newY) = self { x = newX, y = newY }

This is just like a Python class with its explicit self variables. 這就像一個帶有顯式self變量的Python類。 Now that we have a bunch of self → functions, we need to combine them into a single function for the coalgebra. 現在我們有了一堆self →函數,我們需要將它們組合成一個用於代數的單個函數。 We can do this with a simple tuple: 我們可以用一個簡單的元組來做到這一點:

coop ∷ C → ((Int, Int), String, (Int, Int) → C)
coop self = (position self, name self, setPosition self)

The type ((Int, Int), String, (Int, Int) → c) —for any c —is a functor, so coop does have the form we want: Functor f ⇒ C → f C . 類型((Int, Int), String, (Int, Int) → c) - 對於任何 c - 是一個仿函數,所以coop確實具有我們想要的形式: Functor f ⇒ C → f C

Given this, C along with coop form a coalgebra which specifies the class I gave above. 鑑於此, Ccoop構成了一個代數,它指定了我上面給出的類。 You can see how we can use this same technique to specify any number of methods and properties for our objects to have. 您可以看到我們如何使用相同的技術爲對象指定任意數量的方法和屬性。

This lets us use coalgebraic reasoning to deal with classes. 這讓我們可以使用代數推理來處理類。 For example, we can bring in the notion of an "F-coalgebra homomorphism" to represent transformations between classes. 例如,我們可以引入“F-coalgebra同態”的概念來表示類之間的轉換。 This is a scary sounding term that just means a transformation between coalgebras that preserves structure. 這是一個可怕的聲音術語,意味着保留結構的天使之間的轉換。 This makes it much easier to think about mapping classes onto other classes. 這使得考慮將類映射到其他類更容易。

In short, an F-coalgebra represents a class by having a bunch of properties and methods that all depend on a self parameter containing each object's internal state. 簡而言之,F-coalgebra通過擁有一堆屬性和方法來表示一個類,這些屬性和方法都依賴於包含每個對象內部狀態的self參數。

Other Categories 其他類別

So far, we've talked about algebras and coalgebras as Haskell types. 到目前爲止,我們已經將代數和餘代數作爲Haskell類型進行了討論。 An algebra is just a type τ with a function f τ → τ and a coalgebra is just a type τ with a function τ → f τ . 一個代數僅僅是一個類型τ與函數f τ → τ和一個餘代數只是一個類型τ與函數τ → f τ

However, nothing really ties these ideas to Haskell per se . 然而,沒有什麼能真正將這些想法與Haskell 本身聯繫起來 In fact, they're usually introduced in terms of sets and mathematical functions rather than types and Haskell functions. 事實上,它們通常是根據集合和數學函數而不是類型和Haskell函數引入的。 Indeed,we can generalize these concepts to any categories! 實際上,我們可以將這些概念概括爲任何類別!

We can define an F-algebra for some category C . 我們可以爲某些類別C定義F代數。 First, we need a functor F : C → C —that is, an endofunctor . 首先,我們需要一個仿函數F : C → C - 即一個endofunctor (All Haskell Functor s are actually endofunctors from Hask → Hask .) Then, an algebra is just an object A from C with a morphism FA → A . (所有Haskell Functor實際上都是來自Hask → Hask 。)然後,代數只是來自C的對象A ,具有態射FA → A A coalgebra is the same except with A → FA . 除了A → FA之外,餘代數是相同的。

What do we gain by considering other categories? 考慮其他類別我們可以獲得什麼? Well, we can use the same ideas in different contexts. 好吧,我們可以在不同的環境中使用相同的想法。 Like monads. 像單子一樣。 In Haskell, a monad is some type M ∷ ★ → ★ with three operations: 在Haskell中,monad是某種類型的M ∷ ★ → ★有三個操作:

map      ∷ (α → β) → (M α → M β)
return   ∷ α → M α
join     ∷ M (M α) → M α

The map function is just a proof of the fact that M is a Functor . map函數只是MFunctor這一事實的證明。 So we can say that a monad is just a functor with two operations: return and join . 所以我們可以說monad只是一個有兩個操作的仿函數: returnjoin

Functors form a category themselves, with morphisms between them being so-called "natural transformations". 函子本身形成一個類別,它們之間的態射是所謂的“自然變換”。 A natural transformation is just a way to transform one functor into another while preserving its structure. 自然變換隻是將一個仿函數轉換爲另一個仿函數同時保留其結構的一種方法。 Here's a nice article helping explain the idea. 這是一篇很好的文章,有助於解釋這個想法。 It talks about concat , which is just join for lists. 它談論concat ,這是剛剛join的名單。

With Haskell functors, the composition of two functors is a functor itself. 使用Haskell仿函數,兩個仿函數的組合本身就是仿函數。 In pseudocode, we could write this: 在僞代碼中,我們可以這樣寫:

instance (Functor f, Functor g) ⇒ Functor (f ∘ g) where
  fmap fun x = fmap (fmap fun) x

This helps us think about join as a mapping from f ∘ f → f . 這有助於我們將join視爲f ∘ f → f的映射。 The type of join is ∀α. f (f α) → f α 該類型的join∀α. f (f α) → f α ∀α. f (f α) → f α . ∀α. f (f α) → f α Intuitively, we can see how a function valid for all types α can be thought of as a transformation of f . 直觀地,我們可以看到對所有類型α有效的函數如何被認爲是f的變換。

return is a similar transformation. return是一種類似的轉變。 Its type is ∀α. α → f α 它的類型是∀α. α → f α ∀α. α → f α . ∀α. α → f α This looks different—the first α is not "in" a functor! 這看起來不同 - 第一個α不是“in”的仿函數! Happily, we can fix this by adding an identity functor there: ∀α. Identity α → f α 令人高興的是,我們可以通過在那裏添加一個身份∀α. Identity α → f α函數來解決這個問題: ∀α. Identity α → f α ∀α. Identity α → f α . ∀α. Identity α → f α So return is a transformation Identity → f . 所以return是轉換Identity → f

Now we can think about a monad as just an algebra based around some functor f with operations f ∘ f → f and Identity → f . 現在我們可以將monad想象成一個基於f ∘ f → ff的代數,其運算f ∘ f → fIdentity → f Doesn't this look familiar? 這看起來不熟悉嗎? It's very similar to a monoid, which was just some type τ with operations τ × τ → τ and () → τ . 它與幺半羣非常相似,它只是某種類型τ ,其操作τ × τ → τ() → τ

So a monad is just like a monoid, except instead of having a type we have a functor. 所以monad就像一個monoid,除了沒有類型我們有一個functor。 It's the same sort of algebra, just in a different category. 它是同一種代數,只是在不同的類別中。 (This is where the phrase "A monad is just a monoid in the category of endofunctors" comes from as far as I know.) (據我所知,這就是“monad只是endofunctors類別中的monoid”這句話。)

Now, we have these two operations: f ∘ f → f and Identity → f . 現在,我們有這兩個操作: f ∘ f → fIdentity → f To get the corresponding coalgebra, we just flip the arrows. 爲了獲得相應的代數,我們只需翻轉箭頭。 This gives us two new operations: f → f ∘ f and f → Identity . 這給了我們兩個新的操作: f → f ∘ ff → Identity We can turn them into Haskell types by adding type variables as above, giving us ∀α. f α → f (f α) 我們可以通過添加上面的類型變量將它們變成Haskell類型,給我們∀α. f α → f (f α) ∀α. f α → f (f α) and ∀α. f α → α ∀α. f α → α ∀α. f α → f (f α) ∀α. f α → α ∀α. f α → f (f α)∀α. f α → α ∀α. f α → α . ∀α. f α → α This looks just like the definition of a comonad: 這看起來就像comonad的定義:

class Functor f ⇒ Comonad f where
  coreturn ∷ f α → α
  cojoin   ∷ f α → f (f α)

So a comonad is then a coalgebra in a category of endofunctors. 所以comonad然後在endofunctors的類別餘代數


#4樓

F-algebras and F-coalgebras are mathematical structures which are instrumental in reasoning about inductive types (or recursive types ). F-代數和F-餘代數是數學結構,有助於推理歸納類型 (或遞歸類型 )。

F-algebras F-代數

We'll start first with F-algebras. 我們先從F-algebras開始。 I will try to be as simple as possible. 我會盡量簡單。

I guess you know what is a recursive type. 我想你知道什麼是遞歸類型。 For example, this is a type for a list of integers: 例如,這是整數列表的類型:

data IntList = Nil | Cons (Int, IntList)

It is obvious that it is recursive - indeed, its definition refers to itself. 很明顯它是遞歸的 - 實際上,它的定義指的是它自己。 Its definition consists of two data constructors, which have the following types: 它的定義由兩個數據構造函數組成,它們具有以下類型:

Nil  :: () -> IntList
Cons :: (Int, IntList) -> IntList

Note that I have written type of Nil as () -> IntList , not simply IntList . 請注意,我已將Nil類型寫爲() -> IntList ,而不僅僅是IntList These are in fact equivalent types from the theoretical point of view, because () type has only one inhabitant. 從理論的角度來看,這些實際上是等同的類型,因爲()類型只有一個居民。

If we write signatures of these functions in a more set-theoretical way, we will get 如果我們以更集理論的方式編寫這些函數的簽名,我們就會得到

Nil  :: 1 -> IntList
Cons :: Int × IntList -> IntList

where 1 is a unit set (set with one element) and A × B operation is a cross product of two sets A and B (that is, set of pairs (a, b) where a goes through all elements of A and b goes through all elements of B ). 其中1是單位集(用一個元素設置), A × B操作是兩個集合AB的交叉乘積(即成對的集合(a, b) ,其中a經過Ab所有元素去通過B )的所有元素。

Disjoint union of two sets A and B is a set A | B 兩組AB不相交聯合是一組A | B A | B which is a union of sets {(a, 1) : a in A} and {(b, 2) : b in B} . A | B是集合{(a, 1) : a in A}的集合{(a, 1) : a in A} {(b, 2) : b in B} Essentially it is a set of all elements from both A and B , but with each of this elements 'marked' as belonging to either A or B , so when we pick any element from A | B 本質上它是來自AB的所有元素的集合,但是每個元素'標記'屬於AB ,所以當我們從A | B選擇任何元素時 A | B we will immediately know whether this element came from A or from B . A | B我們將立即知道這個元素是來自A還是來自B

We can 'join' Nil and Cons functions, so they will form a single function working on a set 1 | (Int × IntList) 我們可以“加入” NilCons函數,因此它們將構成一個函數,用於集合1 | (Int × IntList) 1 | (Int × IntList) : 1 | (Int × IntList)

Nil|Cons :: 1 | (Int × IntList) -> IntList

Indeed, if Nil|Cons function is applied to () value (which, obviously, belongs to 1 | (Int × IntList) set), then it behaves as if it was Nil ; 實際上,如果將Nil|Cons函數應用於()值(顯然屬於1 | (Int × IntList)集),那麼它的行爲就好像它是Nil ; if Nil|Cons is applied to any value of type (Int, IntList) (such values are also in the set 1 | (Int × IntList) , it behaves as Cons . 如果Nil|Cons應用於任何類型的值(Int, IntList) (這些值也在集合1 | (Int × IntList) ,則表現爲Cons

Now consider another datatype: 現在考慮另一種數據類型:

data IntTree = Leaf Int | Branch (IntTree, IntTree)

It has the following constructors: 它有以下構造函數:

Leaf   :: Int -> IntTree
Branch :: (IntTree, IntTree) -> IntTree

which also can be joined into one function: 也可以加入一個函數:

Leaf|Branch :: Int | (IntTree × IntTree) -> IntTree

It can be seen that both of this joined functions have similar type: they both look like 可以看出,這兩個joined函數都有類似的類型:它們看起來都像

f :: F T -> T

where F is a kind of transformation which takes our type and gives more complex type, which consists of x and | 其中F是一種變換,它採用我們的類型並給出更復雜的類型,它由x| operations, usages of T and possibly other types. 操作, T用法以及可能的其他類型。 For example, for IntList and IntTree F looks as follows: 例如,對於IntListIntTree F ,如下所示:

F1 T = 1 | (Int × T)
F2 T = Int | (T × T)

We can immediately notice that any algebraic type can be written in this way. 我們可以立即注意到任何代數類型都可以用這種方式編寫。 Indeed, that is why they are called 'algebraic': they consist of a number of 'sums' (unions) and 'products' (cross products) of other types. 實際上,這就是爲什麼它們被稱爲“代數”:它們由許多“總和”(工會)和其他類型的“產品”(交叉產品)組成。

Now we can define F-algebra. 現在我們可以定義F代數。 F-algebra is just a pair (T, f) , where T is some type and f is a function of type f :: FT -> T . F代數只是一對(T, f) ,其中T是某種類型, ff :: FT -> T類型的函數。 In our examples F-algebras are (IntList, Nil|Cons) and (IntTree, Leaf|Branch) . 在我們的例子中,F-代數是(IntList, Nil|Cons)(IntTree, Leaf|Branch) Note, however, that despite that type of f function is the same for each F, T and f themselves can be arbitrary. 但是請注意,儘管每種F的f函數類型相同,但Tf本身可以是任意的。 For example, (String, g :: 1 | (Int x String) -> String) or (Double, h :: Int | (Double, Double) -> Double) for some g and h are also F-algebras for corresponding F. 例如,對於某些gh(String, g :: 1 | (Int x String) -> String)(Double, h :: Int | (Double, Double) -> Double)也是對應的F代數F。

Afterwards we can introduce F-algebra homomorphisms and then initial F-algebras , which have very useful properties. 之後我們可以引入F-代數同態 ,然後引入具有非常有用性質的初始F-代數 In fact, (IntList, Nil|Cons) is an initial F1-algebra, and (IntTree, Leaf|Branch) is an initial F2-algebra. 實際上, (IntList, Nil|Cons)是一個初始的F1代數,而(IntTree, Leaf|Branch)是一個初始的F2代數。 I will not present exact definitions of these terms and properties since they are more complex and abstract than needed. 我不會提供這些術語和屬性的確切定義,因爲它們比需要的更復雜和抽象。

Nonetheless, the fact that, say, (IntList, Nil|Cons) is F-algebra allows us to define fold -like function on this type. 但是,事實上, (IntList, Nil|Cons)是F代數允許我們在這種類型上定義類似fold的函數。 As you know, fold is a kind of operation which transforms some recursive datatype in one finite value. 如您所知,fold是一種將一些遞歸數據類型轉換爲一個有限值的操作。 For example, we can fold a list of integer into a single value which is a sum of all elements in the list: 例如,我們可以將整數列表摺疊爲單個值,該值是列表中所有元素的總和:

foldr (+) 0 [1, 2, 3, 4] -> 1 + 2 + 3 + 4 = 10

It is possible to generalize such operation on any recursive datatype. 可以在任何遞歸數據類型上概括此類操作。

The following is a signature of foldr function: 以下是foldr函數的簽名:

foldr :: ((a -> b -> b), b) -> [a] -> b

Note that I have used braces to separate first two arguments from the last one. 請注意,我使用大括號將前兩個參數與最後一個參數分開。 This is not real foldr function, but it is isomorphic to it (that is, you can easily get one from the other and vice versa). 這不是真正的foldr函數,但它是同構的(也就是說,你可以很容易地從另一箇中得到一個,反之亦然)。 Partially applied foldr will have the following signature: 部分應用的foldr將具有以下簽名:

foldr ((+), 0) :: [Int] -> Int

We can see that this is a function which takes a list of integers and returns a single integer. 我們可以看到這是一個函數,它獲取整數列表並返回一個整數。 Let's define such function in terms of our IntList type. 讓我們IntList類型定義這樣的函數。

sumFold :: IntList -> Int
sumFold Nil         = 0
sumFold (Cons x xs) = x + sumFold xs

We see that this function consists of two parts: first part defines this function's behavior on Nil part of IntList , and second part defines function's behavior on Cons part. 我們看到這個函數由兩部分組成:第一部分在IntList Nil部分定義了這個函數的行爲,第二部分在Cons部分定義了函數的行爲。

Now suppose that we are programming not in Haskell but in some language which allows usage of algebraic types directly in type signatures (well, technically Haskell allows usage of algebraic types via tuples and Either ab datatype, but this will lead to unnecessary verbosity). 現在假設我們不是在Haskell中編程,而是在某種語言中允許直接在類型簽名中使用代數類型(從技術上講,Haskell允許通過元組和Either ab數據類型來使用代數類型,但這會導致不必要的冗長)。 Consider a function: 考慮一個功能:

reductor :: () | (Int × Int) -> Int
reductor ()     = 0
reductor (x, s) = x + s

It can be seen that reductor is a function of type F1 Int -> Int , just as in definition of F-algebra! 可以看出, reductorF1 Int -> Int類型的函數,就像F代數的定義一樣! Indeed, the pair (Int, reductor) is an F1-algebra. 實際上,這對(Int, reductor)是一個F1代數。

Because IntList is an initial F1-algebra, for each type T and for each function r :: F1 T -> T there exist a function, called catamorphism for r , which converts IntList to T , and such function is unique. 因爲IntList是初始F1-代數,對於每種類型T和每個功能r :: F1 T -> T存在的函數,稱爲catamorphismr它轉換IntListT ,並且這樣的功能是唯一的。 Indeed, in our example a catamorphism for reductor is sumFold . 實際上,在我們的例子中,縮減reductorsumFoldsumFold Note how reductor and sumFold are similar: they have almost the same structure! 注意reductorsumFold是如何相似的:它們具有幾乎相同的結構! In reductor definition s parameter usage (type of which corresponds to T ) corresponds to usage of the result of computation of sumFold xs in sumFold definition. reductor定義s參數用法(其類型對應於T )對應於計算結果的使用sumFold xssumFold定義。

Just to make it more clear and help you see the pattern, here is another example, and we again begin from the resulting folding function. 只是爲了讓它更清晰並幫助你看到模式,這是另一個例子,我們再次從得到的摺疊函數開始。 Consider append function which appends its first argument to second one: 考慮append函數,將第一個參數追加到第二個參數:

(append [4, 5, 6]) [1, 2, 3] = (foldr (:) [4, 5, 6]) [1, 2, 3] -> [1, 2, 3, 4, 5, 6]

This how it looks on our IntList : 這是它在我們的IntList上的IntList

appendFold :: IntList -> IntList -> IntList
appendFold ys ()          = ys
appendFold ys (Cons x xs) = x : appendFold ys xs

Again, let's try to write out the reductor: 再次,讓我們嘗試寫出縮減器:

appendReductor :: IntList -> () | (Int × IntList) -> IntList
appendReductor ys ()      = ys
appendReductor ys (x, rs) = x : rs

appendFold is a catamorphism for appendReductor which transforms IntList into IntList . appendFoldappendReductor一個catamorphism,它將IntList轉換爲IntList

So, essentially, F-algebras allow us to define 'folds' on recursive datastructures, that is, operations which reduce our structures to some value. 因此,基本上,F代數允許我們在遞歸數據結構上定義“摺疊”,即將結構減少到某個值的操作。

F-coalgebras F-餘代數

F-coalgebras are so-called 'dual' term for F-algebras. F-coalgebras是F-algebras的所謂“雙重”術語。 They allow us to define unfolds for recursive datatypes, that is, a way to construct recursive structures from some value. 它們允許我們爲遞歸數據類型定義unfolds ,即從某個值構造遞歸結構的方法。

Suppose you have the following type: 假設您有以下類型:

data IntStream = Cons (Int, IntStream)

This is an infinite stream of integers. 這是一個無限的整數流。 Its only constructor has the following type: 它唯一的構造函數具有以下類型:

Cons :: (Int, IntStream) -> IntStream

Or, in terms of sets 或者,就集合而言

Cons :: Int × IntStream -> IntStream

Haskell allows you to pattern match on data constructors, so you can define the following functions working on IntStream s: Haskell允許您對數據構造函數進行模式匹配,因此您可以定義在IntStreamIntStream的以下函數:

head :: IntStream -> Int
head (Cons (x, xs)) = x

tail :: IntStream -> IntStream
tail (Cons (x, xs)) = xs

You can naturally 'join' these functions into single function of type IntStream -> Int × IntStream : 您可以自然地將這些函數“連接”到IntStream -> Int × IntStream類型的單個函數中IntStream -> Int × IntStream

head&tail :: IntStream -> Int × IntStream
head&tail (Cons (x, xs)) = (x, xs)

Notice how the result of the function coincides with algebraic representation of our IntStream type. 注意函數的結果如何與我們的IntStream類型的代數表示一致。 Similar thing can also be done for other recursive data types. 對於其他遞歸數據類型也可以執行類似的操作。 Maybe you already have noticed the pattern. 也許你已經注意到了這種模式。 I'm referring to a family of functions of type 我指的是一系列類型的函數

g :: T -> F T

where T is some type. 其中T是某種類型。 From now on we will define 從現在開始,我們將定義

F1 T = Int × T

Now, F-coalgebra is a pair (T, g) , where T is a type and g is a function of type g :: T -> FT . 現在, F-coalgebra是一對(T, g) ,其中T是一個類型, gg :: T -> FT類型的函數。 For example, (IntStream, head&tail) is an F1-coalgebra. 例如, (IntStream, head&tail)是F1-coalgebra。 Again, just as in F-algebras, g and T can be arbitrary, for example, (String, h :: String -> Int x String) is also an F1-coalgebra for some h. 同樣,就像在F-algebras中一樣, gT可以是任意的,例如, (String, h :: String -> Int x String)也是某些h的F1-代數。

Among all F-coalgebras there are so-called terminal F-coalgebras , which are dual to initial F-algebras. 在所有的F-coalgebras中都有所謂的終端F-餘代數 ,它們是初始F-代數的雙重代數。 For example, IntStream is a terminal F-coalgebra. 例如, IntStream是終端F-代數。 This means that for every type T and for every function p :: T -> F1 T there exist a function, called anamorphism , which converts T to IntStream , and such function is unique. 這意味着對於每個類型T和每個函數p :: T -> F1 T ,存在一個稱爲變形的函數,它將T轉換爲IntStream ,並且這樣的函數是唯一的。

Consider the following function, which generates a stream of successive integers starting from the given one: 考慮以下函數,它從給定的一個開始生成連續整數的流:

nats :: Int -> IntStream
nats n = Cons (n, nats (n+1))

Now let's inspect a function natsBuilder :: Int -> F1 Int , that is, natsBuilder :: Int -> Int × Int : 現在讓我們檢查函數natsBuilder :: Int -> F1 Int ,即natsBuilder :: Int -> Int × Int

natsBuilder :: Int -> Int × Int
natsBuilder n = (n, n+1)

Again, we can see some similarity between nats and natsBuilder . 同樣,我們可以看到的一些相似natsnatsBuilder It is very similar to the connection we have observed with reductors and folds earlier. 它與我們之前在減速器和摺疊中觀察到的連接非常相似。 nats is an anamorphism for natsBuilder . natsnatsBuilder的變形natsBuilder

Another example, a function which takes a value and a function and returns a stream of successive applications of the function to the value: 另一個例子,一個函數,它接受一個值和一個函數,並將函數的連續應用程序流返回給值:

iterate :: (Int -> Int) -> Int -> IntStream
iterate f n = Cons (n, iterate f (f n))

Its builder function is the following one: 它的構建器功能如下:

iterateBuilder :: (Int -> Int) -> Int -> Int × Int
iterateBuilder f n = (n, f n)

Then iterate is an anamorphism for iterateBuilder . 然後, iterateiterateBuilder一個變形iterateBuilder

Conclusion 結論

So, in short, F-algebras allow to define folds, that is, operations which reduce recursive structure down into a single value, and F-coalgebras allow to do the opposite: construct a [potentially] infinite structure from a single value. 因此,簡而言之,F-代數允許定義摺疊,即將遞歸結構減少爲單個值的操作,而F-coalgebras允許相反:從單個值構造[潛在]無限結構。

In fact in Haskell F-algebras and F-coalgebras coincide. 事實上在Haskell F-algebras和F-coalgebras重合。 This is a very nice property which is a consequence of presence of 'bottom' value in each type. 這是一個非常好的屬性,這是每種類型中存在“底部”值的結果。 So in Haskell both folds and unfolds can be created for every recursive type. 所以在Haskell中,可以爲每個遞歸類型創建摺疊和展開。 However, theoretical model behind this is more complex than the one I have presented above, so I deliberately have avoided it. 然而,這背後的理論模型比我上面提到的更復雜,所以我故意避免它。

Hope this helps. 希望這可以幫助。


#5樓

I'll start with stuff that is obviously programming-related and then add on some mathematics stuff, to keep it as concrete and down-to-earth as I can. 我將從顯然與編程相關的東西開始,然後添加一些數學內容,儘可能保持具體和腳踏實地。


Let's quote some computer-scientists on coinduction… 讓我們引用一些關於coinduction的計算機科學家的話......

http://www.cs.umd.edu/~micinski/posts/2012-09-04-on-understanding-coinduction.html http://www.cs.umd.edu/~micinski/posts/2012-09-04-on-understanding-coinduction.html

Induction is about finite data, co-induction is about infinite data. 歸納是關於有限數據,共同歸納是關於無限數據。

The typical example of infinite data is the type of a lazy list (a stream). 無限數據的典型示例是惰性列表(流)的類型。 For example, lets say that we have the following object in memory: 例如,假設我們在內存中有以下對象:

 let (pi : int list) = (* some function which computes the digits of
 π. *)

The computer can't hold all of π, because it only has a finite amount of memory! 計算機不能保持所有的π,因爲它只有有限的內存! But what it can do is hold a finite program, which will produce any arbitrarily long expansion of π that you desire. 但它能做的是持有一個有限的程序,它會產生你想要的任意長度的π擴展。 As long as you only use finite pieces of the list, you can compute with that infinite list as much as you need. 只要您只使用列表中的有限部分,就可以根據需要使用該無限列表進行計算。

However, consider the following program: 但是,請考慮以下程序:

let print_third_element (k : int list) =   match k with
     | _ :: _ :: thd :: tl -> print thd


 print_third_element pi

This program should print the third digit of pi. 該程序應打印pi的第三個數字。 But in some languages, any argument to a function is evaluated before being passed into a function (strict, not lazy, evaluation). 但是在某些語言中,函數的任何參數在傳遞給函數之前都會被計算(嚴格,而不是惰性,評估)。 If we use this reduction order, then our above program will run forever computing the digits of pi before it can be passed to our printer function (which never happens). 如果我們使用這個減少順序,那麼我們上面的程序將永遠運行計算pi的數字,然後才能傳遞給我們的打印機功能(從未發生)。 Since the machine does not have infinite memory, the program will eventually run out of memory and crash. 由於機器沒有無限的內存,程序最終會耗盡內存並崩潰。 This might not be the best evaluation order. 這可能不是最好的評估順序。

http://adam.chlipala.net/cpdt/html/Coinductive.html http://adam.chlipala.net/cpdt/html/Coinductive.html

In lazy functional programming languages like Haskell, infinite data structures are everywhere. 在像Haskell這樣的惰性函數式編程語言中,無處不在的數據結構。 Infinite lists and more exotic datatypes provide convenient abstractions for communication between parts of a program. 無限列表和更奇特的數據類型爲程序各部分之間的通信提供了方便的抽象。 Achieving similar convenience without infinite lazy structures would, in many cases, require acrobatic inversions of control flow. 在許多情況下,在沒有無限懶惰結構的情況下實現類似的便利性將需要控制流的特技反轉。

http://www.alexandrasilva.org/#/talks.html http://www.alexandrasilva.org/#/talks.html 亞歷山德拉席爾瓦的代數的例子


Relating the ambient mathematical context to usual programming tasks 將環境數學上下文與通常的編程任務相關聯

What is "an algebra"? 什麼是“代數”?

Algebraic structures generally look like: 代數結構通常如下所示:

  1. Stuff 東西
  2. What the stuff can do 這些東西可以做什麼

This should sound like objects with 1. properties and 2. methods. 這應該聽起來像1.屬性和2.方法的對象。 Or even better, it should sound like type signatures. 或者甚至更好,它應該聽起來像類型簽名。

Standard mathematical examples include monoid ⊃ group ⊃ vector-space ⊃ "an algebra". 標準數學例子包括monoid⊃group⊃矢量空間⊃“代數”。 Monoids are like automata: sequences of verbs (eg, fghhnothing.fgf ). 幺半羣就像自動機:動詞序列(例如, fghhnothing.fgf )。 A git log that always adds history and never deletes it would be a monoid but not a group. 總是添加歷史記錄並且永遠不會刪除它的git日誌將是一個monoid而不是一個組。 If you add inverses (eg negative numbers, fractions, roots, deleting accumulated history, un-shattering a broken mirror) you get a group. 如果你添加了反轉(例如負數,分數,根,刪除累積的歷史記錄,不破壞破碎的鏡像),你會得到一個組。

Groups contain things that can be added or subtracted together. 組包含可以一起添加或減去的內容。 For example Duration s can be added together. 例如,可以將Duration s加在一起。 (But Date s cannot.) Durations live in a vector-space (not just a group) because they can also be scaled by outside numbers. (但是Date不能。)持續時間存在於向量空間(不僅僅是一個組),因爲它們也可以通過外部數字進行縮放。 (A type signature of scaling :: (Number,Duration) → Duration .) scaling :: (Number,Duration) → Duration的類型簽名scaling :: (Number,Duration) → Duration 。)

Algebras ⊂ vector-spaces can do yet another thing: there's some m :: (T,T) → T . 代數⊂向量空間可以做另一件事:有一些m :: (T,T) → T Call this "multiplication" or don't, because once you leave Integers it's less obvious what "multiplication" (or "exponentiation" ) should be. 稱之爲“乘法”或不這樣做,因爲一旦你離開Integers ,那麼“乘法”(或“取冪” )應該是什麼不太明顯。

(This is why people look to (category-theoretic) universal properties: to tell them what multiplication should do or be like : (這就是人們關注(類別理論)通用屬性的原因:告訴他們乘法應該做什麼或者什麼樣的

產品的普遍屬性)


Algebras → Coalgebras 代數→Coalgebras

Comultiplication is easier to define in a way that feels non-arbitrary, than is multiplication, because to go from T → (T,T) you can just repeat the same element. 與乘法相比,乘法更容易以感覺非任意的方式定義,因爲從T → (T,T)你可以重複相同的元素。 ("diagonal map" – like diagonal matrices/operators in spectral theory) (“對角線圖” - 類似於光譜理論中的對角矩陣/算子)

Counit is usually the trace (sum of diagonal entries), although again what's important is what your counit does ; 計數通常是跟蹤(對角線條目的總和),儘管重要的是你的國家所做的事情; trace is just a good answer for matrices. trace只是矩陣的一個很好的答案。

The reason to look at a dual space , in general, is because it's easier to think in that space. 一般來說,看待雙重空間的原因是因爲在這個空間中思考更容易。 For example it's sometimes easier to think about a normal vector than about the plane it's normal to, but you can control planes (including hyperplanes) with vectors (and now I'm speaking of the familiar geometric vector, like in a ray-tracer). 例如,考慮法向量有時比考慮它的法線更容易,但你可以用向量控制平面(包括超平面)(現在我說的是熟悉的幾何向量,就像在光線跟蹤器中一樣) 。


Taming (un)structured data 馴服(非)結構化數據

Mathematicians might be modelling something fun like TQFT's , whereas programmers have to wrestle with 數學家可能會像TQFT那樣建模有趣的東西,而程序員則必須與之搏鬥

  • dates/times ( + :: (Date,Duration) → Date ), 日期/時間( + :: (Date,Duration) → Date ),
  • places ( Paris(+48.8567,+2.3508) ! It's a shape, not a point.), 地方( Paris(+48.8567,+2.3508) !這是一個形狀,而不是一個點。),
  • unstructured JSON which is supposed to be consistent in some sense, 非結構化的JSON,在某種意義上應該是一致的,
  • wrong-but-close XML, 錯誤但非常接近的XML,
  • incredibly complex GIS data which should satisfy loads of sensible relations, 非常複雜的GIS數據,應該滿足合理的關係,
  • regular expressions which meant something to you, but mean considerably less to perl. 正則表達式對你來說意味着什麼,但對perl意味着更少。
  • CRM that should hold all the executive's phone numbers and villa locations, his (now ex-) wife and kids' names, birthday and all the previous gifts, each of which should satisfy "obvious" relations (obvious to the customer) which are incredibly hard to code up, CRM應該包含所有行政人員的電話號碼和別墅位置,他(現在的前妻)和孩子的名字,生日和所有以前的禮物,每個都應該滿足“顯而易見”的關係(對顧客來說很明顯),這是令人難以置信的難以編碼,
  • ..... .....

Computer scientists, when talking about coalgebras, usually have set-ish operations in mind, like Cartesian product. 計算機科學家在談論代數時,通常會考慮定製操作,就像笛卡爾積。 I believe this is what people mean when they say like "Algebras are coalgebras in Haskell". 我相信當人們說“代數是哈斯克爾的代數”時,這就是人們的意思。 But to the extent that programmers have to model complex data-types like Place , Date/Time , and Customer —and make those models look as much like the real world (or at least the end-user's view of the real world) as possible—I believe duals, could be useful beyond only set-world. 但是程序員必須對像PlaceDate/TimeCustomer這樣的複雜數據類型進行建模,並使這些模型看起來儘可能像現實世界(或者至少是最終用戶對現實世界的看法) - 我相信雙重身份,可能只有在世界範圍內有用。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章