Já ouvi o termo "coalgebras" várias vezes na programação funcional e nos círculos PLT, especialmente quando a discussão é sobre objetos, comonadas, lentes e outros. Pesquisando esse termo, páginas trazem descrições matemáticas dessas estruturas, que são praticamente incompreensíveis para mim. Alguém pode, por favor, explicar o que as barras de carvão significam no contexto da programação, qual é o significado delas e como elas se relacionam com objetos e comônadas?
scala
haskell
functional-programming
category-theory
recursion-schemes
desaparecido
fonte
fonte
Respostas:
Álgebras
Eu acho que o ponto de partida seria entender a idéia de uma álgebra . Esta é apenas uma generalização de estruturas algébricas como grupos, anéis, monóides e assim por diante. Na maioria das vezes, essas coisas são introduzidas em termos de conjuntos, mas como estamos entre amigos, falarei sobre os tipos de Haskell. (Mas não resisto a usar algumas letras gregas - elas fazem tudo parecer mais legal!)
Uma álgebra, então, é apenas um tipo
τ
com algumas funções e identidades. Essas funções recebem diferentes números de argumentos do tipoτ
e produzem aτ
: uncurried, todas elas se parecem(τ, τ,…, τ) → τ
. Eles também podem ter "identidades" - elementosτ
que têm um comportamento especial com algumas das funções.O exemplo mais simples disso é o monóide. Um monóide é qualquer tipo
τ
com uma funçãomappend ∷ (τ, τ) → τ
e uma identidademzero ∷ τ
. Outros exemplos incluem coisas como grupos (que são como monóides, exceto com umainvert ∷ τ → τ
função extra ), anéis, treliças e assim por diante.Todas as funções operam,
τ
mas podem ter diferentes áreas. Podemos escrever isso comoτⁿ → τ
, ondeτⁿ
mapeia para uma tupla den
τ
. Dessa forma, faz sentido pensar em identidades comoτ⁰ → τ
ondeτ⁰
está apenas a tupla vazia()
. Então, na verdade, podemos simplificar a idéia de uma álgebra agora: é apenas um tipo com algum número de funções.Uma álgebra é apenas um padrão comum em matemática que foi "fatorado", assim como fazemos com o código. As pessoas notaram que um monte de coisas interessantes - os mencionados monoides, grupos, treliças e assim por diante - seguem um padrão semelhante, então eles abstraem. A vantagem de fazer isso é a mesma da programação: cria provas reutilizáveis e facilita certos tipos de raciocínio.
Álgebras F
No entanto, ainda não terminamos o fatoramento. Até agora, temos várias funções
τⁿ → τ
. Na verdade, podemos fazer um truque para combiná-los em uma única função. Em particular, vejamos os monoides: temosmappend ∷ (τ, τ) → τ
emempty ∷ () → τ
. Podemos transformá-los em uma única função usando um tipo de soma—Either
. Seria assim:Podemos realmente usar essa transformação repetidamente para combinar todas as
τⁿ → τ
funções em uma única, para qualquer álgebra. (Na verdade, podemos fazer isso por qualquer número de funçõesa → τ
,b → τ
e assim por diante para qualquera, b,…
.)Isso nos permite falar sobre álgebras como um tipo
τ
com uma única função, de alguma confusão deEither
s para um únicoτ
. Para monoids, esta confusão é:Either (τ, τ) ()
; para grupos (que têm um extra deτ → τ
operação), é:Either (Either (τ, τ) τ) ()
. É um tipo diferente para cada estrutura diferente. Então, o que todos esses tipos têm em comum? O mais óbvio é que todos são apenas somas de produtos - tipos de dados algébricos. Por exemplo, para monóides, podemos criar um tipo de argumento monóide que funcione para qualquer monóide τ:Podemos fazer o mesmo com grupos, anéis, treliças e todas as outras estruturas possíveis.
O que mais há de especial em todos esses tipos? Bem, são todos
Functors
! Por exemplo:Assim, podemos generalizar ainda mais a nossa ideia de álgebra. É apenas algum tipo
τ
com uma funçãof τ → τ
para algum functorf
. De fato, poderíamos escrever isso como uma classe:Isso geralmente é chamado de "álgebra F" porque é determinado pelo functor
F
. Se pudéssemos aplicar parcialmente classes de tipos, poderíamos definir algo comoclass Monoid = Algebra MonoidArgument
.Coalgebras
Agora, espero que você tenha uma boa noção do que é uma álgebra e como é apenas uma generalização de estruturas algébricas normais. Então, o que é um F-coalgebra? Bem, o co implica que é o "dual" de uma álgebra - isto é, pegamos uma álgebra e lançamos algumas flechas. Eu vejo apenas uma seta na definição acima, então eu vou virar isso:
E é só isso! Agora, essa conclusão pode parecer um pouco irreverente (heh). Ele mostra o que é uma coalgebra, mas na verdade não fornece nenhuma ideia de como é útil ou por que nos importamos. Eu chegarei a isso daqui a pouco, quando encontrar ou apresentar um bom exemplo ou dois: P.
Classes e Objetos
Depois de ler um pouco, acho que tenho uma boa idéia de como usar barras de carvão para representar classes e objetos. Temos um tipo
C
que contém todos os possíveis estados internos de objetos na classe; a classe em si é uma coalgebra sobre aC
qual especifica os métodos e propriedades dos objetos.Conforme mostrado no exemplo de álgebra, se tivermos várias funções como
a → τ
eb → τ
para qualquera, b,…
, podemos combiná-las em uma única função usandoEither
um tipo de soma. A "noção" dupla combinaria várias funções do tipoτ → a
,τ → b
e assim por diante. Podemos fazer isso usando o duplo de um tipo de soma - um tipo de produto. Portanto, dadas as duas funções acima (chamadasf
eg
), podemos criar uma única assim:O tipo
(a, a)
é um functor da maneira direta, por isso certamente se encaixa com a nossa noção de um F-coalgebra. Esse truque em particular nos permite agrupar várias funções diferentes - ou, para OOP, métodos - em uma única função do tipoτ → f τ
.Os elementos do nosso tipo
C
representam o estado interno do objeto. Se o objeto tiver algumas propriedades legíveis, ele deverá poder depender do estado. A maneira mais óbvia de fazer isso é torná-las uma funçãoC
. Portanto, se queremos uma propriedade length (por exemploobject.length
), teríamos uma funçãoC → Int
.Queremos métodos que possam levar um argumento e modificar o estado. Para fazer isso, precisamos pegar todos os argumentos e produzir um novo
C
. Vamos imaginar umsetPosition
método que leva umax
e umay
de coordenadas:object.setPosition(1, 2)
. Ele ficaria assim:C → ((Int, Int) → C)
.O padrão importante aqui é que os "métodos" e "propriedades" do objeto tomam o próprio objeto como seu primeiro argumento. É exatamente como o
self
parâmetro em Python e como implícitothis
em muitas outras linguagens. A coálgebra essencialmente apenas encapsula o comportamento de tomar umself
parâmetro: é isso que o primeiroC
emC → F C
se.Então, vamos juntar tudo. Vamos imaginar uma classe com uma
position
propriedade, umaname
propriedade esetPosition
função:Precisamos de duas partes para representar esta classe. Primeiro, precisamos representar o estado interno do objeto; neste caso, apenas contém dois se
Int
umString
. (Esse é o nosso tipoC
.) Então precisamos criar a coalgebra que representa a classe.Temos duas propriedades para escrever. Eles são bastante triviais:
Agora só precisamos ser capazes de atualizar a posição:
É como uma classe Python com suas
self
variáveis explícitas . Agora que temos váriasself →
funções, precisamos combiná-las em uma única função para a coalgebra. Podemos fazer isso com uma tupla simples:O tipo
((Int, Int), String, (Int, Int) → c)
-por qualquerc
-é um functor, por issocoop
tem a forma que queremos:Functor f ⇒ C → f C
.Diante disso,
C
juntamente com acoop
forma de uma coalgebra, especifica a classe que dei acima. Você pode ver como podemos usar essa mesma técnica para especificar qualquer número de métodos e propriedades para nossos objetos.Isso nos permite usar o raciocínio coalgéico para lidar com as classes. Por exemplo, podemos introduzir a noção de um "homomorfismo F-coalgebra" para representar transformações entre classes. Este é um termo assustador que significa apenas uma transformação entre barras de carvão que preserva a estrutura. Isso torna muito mais fácil pensar em mapear classes para outras classes.
Em resumo, um F-coalgebra representa uma classe por possuir várias propriedades e métodos que dependem de um
self
parâmetro que contém o estado interno de cada objeto.Outras categorias
Até agora, falamos sobre álgebras e coalgebras como tipos Haskell. Uma álgebra é apenas um tipo
τ
com uma funçãof τ → τ
e uma coalgebra é apenas um tipoτ
com uma funçãoτ → f τ
.No entanto, nada realmente vincula essas idéias a Haskell em si . De fato, eles geralmente são introduzidos em termos de conjuntos e funções matemáticas, em vez de tipos e funções Haskell. De fato, podemos generalizar esses conceitos para qualquer categoria!
Podemos definir uma álgebra F para alguma categoria
C
. Primeiro, precisamos de um functorF : C → C
- ou seja, um endofunctor . (All HaskellFunctor
s são realmente endofunctors deHask → Hask
.) Então, uma álgebra é apenas um objetoA
a partir deC
uma morphismF A → A
. Uma coalgebra é a mesma, exceto comA → F A
.O que ganhamos ao considerar outras categorias? Bem, podemos usar as mesmas idéias em diferentes contextos. Como mônadas. Em Haskell, uma mônada é algum tipo
M ∷ ★ → ★
com três operações:A
map
função é apenas uma prova do fato de queM
é aFunctor
. Então, podemos dizer que uma mônada é apenas um functor com duas operações:return
ejoin
.Os próprios fundores formam uma categoria, com os morfismos entre eles sendo chamados de "transformações naturais". Uma transformação natural é apenas uma maneira de transformar um functor em outro, preservando sua estrutura. Aqui está um bom artigo que ajuda a explicar a ideia. Ele fala sobre
concat
, que é apenasjoin
para listas.Com os functores Haskell, a composição de dois functores é um próprio functor. No pseudocódigo, poderíamos escrever o seguinte:
Isso nos ajuda a pensar
join
como um mapeamentof ∘ f → f
. O tipo dejoin
é∀α. f (f α) → f α
. Intuitivamente, podemos ver como uma função válida para todos os tiposα
pode ser pensada como uma transformação def
.return
é uma transformação semelhante. Seu tipo é∀α. α → f α
. Isso parece diferente - o primeiroα
não está "em" um functor! Felizmente, nós podemos corrigir isso adicionando um functor identidade aí:∀α. Identity α → f α
. Entãoreturn
é uma transformaçãoIdentity → f
.Agora podemos pensar em uma mônada como apenas uma álgebra baseada em algum functor
f
com operaçõesf ∘ f → f
eIdentity → f
. Isso não parece familiar? É muito parecido com um monóide, que era apenas algum tipoτ
com operaçõesτ × τ → τ
e() → τ
.Portanto, uma mônada é como um monóide, exceto que, em vez de ter um tipo, temos um functor. É o mesmo tipo de álgebra, apenas em uma categoria diferente. (É aqui que a frase "Uma mônada é apenas um monóide na categoria de endofuncores" vem até onde eu sei.)
Agora, temos essas duas operações:
f ∘ f → f
eIdentity → f
. Para obter a correspondente coalgebra, basta girar as setas. Isso nos dá duas novas operações:f → f ∘ f
ef → Identity
. Podemos transformá-los em tipos Haskell adicionando variáveis de tipo como acima, fornecendo-nos∀α. f α → f (f α)
e∀α. f α → α
. Isso se parece com a definição de uma comonada:Então uma comonada é então uma coalgebra em uma categoria de endofuncionadores.
fonte
(,)
e o functor de identidade a()
. Um objeto monóide dentro de uma categoria monoidal é um objeto com setas correspondentes à sua álgebra monóide, que descreve um objeto monóide em Hask com tipos de produtos como a estrutura monoidal. Um objeto monóide na categoria de endofunitores em C é uma mônada em C; portanto, sim, seu entendimento está correto. :]Álgebras-F e barras-carvão são estruturas matemáticas que são instrumentais no raciocínio sobre tipos indutivos (ou recursivos ).
Álgebras F
Vamos começar primeiro com álgebras F. Vou tentar ser o mais simples possível.
Eu acho que você sabe o que é um tipo recursivo. Por exemplo, este é um tipo para uma lista de números inteiros:
É óbvio que é recursivo - de fato, sua definição se refere a si mesma. Sua definição consiste em dois construtores de dados, que têm os seguintes tipos:
Note que eu escrevi o tipo de
Nil
as() -> IntList
, não simplesmenteIntList
. De fato, são tipos equivalentes do ponto de vista teórico, porque o()
tipo tem apenas um habitante.Se escrevermos assinaturas dessas funções de uma maneira mais teórica, obteremos
onde
1
é um conjunto de unidades (conjunto com um elemento) eA × B
operação é um produto cruzado de dois conjuntosA
eB
(ou seja, conjunto de pares(a, b)
ondea
passa por todos os elementos deA
eb
passa por todos os elementos deB
).União disjunta de dois conjuntos
A
eB
é um conjuntoA | B
que é uma união de conjuntos{(a, 1) : a in A}
e{(b, 2) : b in B}
. Essencialmente, é um conjunto de todos os elementos de ambosA
eB
, mas com cada um desses elementos 'marcados' como pertencentes a umA
ou outroB
, portanto, quando escolhermos qualquer elemento,A | B
saberemos imediatamente se esse elemento veioA
ou nãoB
.Podemos 'juntar-se'
Nil
eCons
funções, para que eles formem uma única função trabalhando em um conjunto1 | (Int × IntList)
:De fato, se a
Nil|Cons
função é aplicada ao()
valor (que obviamente pertence ao1 | (Int × IntList)
conjunto), ela se comporta como se fosseNil
; seNil|Cons
for aplicado a qualquer valor do tipo(Int, IntList)
(esses valores também estão no conjunto1 | (Int × IntList)
, ele se comporta comoCons
.Agora considere outro tipo de dados:
Possui os seguintes construtores:
que também pode ser associado a uma função:
Pode-se ver que essas duas
joined
funções têm um tipo semelhante: ambas se parecemonde
F
é um tipo de transformação que leva o nosso tipo e dá tipo mais complexo, que consiste emx
e|
operações, usosT
e possivelmente outros tipos. Por exemplo, paraIntList
eIntTree
F
tem a seguinte aparência:Podemos notar imediatamente que qualquer tipo algébrico pode ser escrito dessa maneira. De fato, é por isso que eles são chamados de 'algébricos': eles consistem em um número de 'somas' (uniões) e 'produtos' (produtos cruzados) de outros tipos.
Agora podemos definir álgebra F. A álgebra F é apenas um par
(T, f)
, ondeT
é algum tipo ef
é uma função do tipof :: F T -> T
. Nos nossos exemplos, as álgebras F são(IntList, Nil|Cons)
e(IntTree, Leaf|Branch)
. Observe, no entanto, que, apesar desse tipo def
função, é o mesmo para cada F,T
ef
elas próprias podem ser arbitrárias. Por exemplo,(String, g :: 1 | (Int x String) -> String)
ou(Double, h :: Int | (Double, Double) -> Double)
para alguns,g
eh
também são álgebras F para F. correspondentePosteriormente, podemos introduzir homomorfismos da álgebra F e, em seguida , álgebras F iniciais , que possuem propriedades muito úteis. De fato,
(IntList, Nil|Cons)
é uma álgebra F1 inicial e(IntTree, Leaf|Branch)
é uma álgebra F2 inicial. Não apresentarei definições exatas desses termos e propriedades, pois são mais complexos e abstratos do que o necessário.No entanto, o fato de, digamos,
(IntList, Nil|Cons)
ser álgebra F, permite definirfold
funções semelhantes a esse tipo. Como você sabe, fold é um tipo de operação que transforma algum tipo de dados recursivo em um valor finito. Por exemplo, podemos dobrar uma lista de números inteiros em um único valor, que é uma soma de todos os elementos da lista:É possível generalizar essa operação em qualquer tipo de dados recursivo.
A seguir, é uma assinatura da
foldr
função:Observe que usei chaves para separar os dois primeiros argumentos do último. Essa não é uma
foldr
função real , mas é isomórfica (ou seja, você pode facilmente obter uma da outra e vice-versa). Parcialmente aplicadofoldr
terá a seguinte assinatura:Podemos ver que essa é uma função que pega uma lista de números inteiros e retorna um único número inteiro. Vamos definir essa função em termos do nosso
IntList
tipo.Vemos que essa função consiste em duas partes: a primeira parte define o comportamento dessa função em
Nil
parteIntList
e a segunda parte define o comportamento da função emCons
parte.Agora, suponha que não estamos programando em Haskell, mas em alguma linguagem que permita o uso de tipos algébricos diretamente nas assinaturas de tipo (bem, tecnicamente, o Haskell permite o uso de tipos algébricos por tuplas e
Either a b
tipos de dados, mas isso levará a verbosidade desnecessária). Considere uma função:Pode-se ver que
reductor
é uma função do tipoF1 Int -> Int
, assim como na definição da álgebra F! De fato, o par(Int, reductor)
é uma álgebra F1.Como
IntList
é uma álgebra F1 inicial, para cada tipoT
e funçãor :: F1 T -> T
existe uma função chamada catamorfismo parar
, que se converteIntList
emT
, e essa função é única. De fato, em nosso exemplo um catamorphism parareductor
ésumFold
. Observe comoreductor
esumFold
são semelhantes: eles têm quase a mesma estrutura! Nareductor
definição, os
uso do parâmetro (do tipo corresponde aT
) corresponde ao uso do resultado da computação desumFold xs
nasumFold
definição.Apenas para torná-lo mais claro e ajudá-lo a ver o padrão, aqui está outro exemplo, e começamos novamente a partir da função de dobra resultante. Considere a
append
função que anexa seu primeiro argumento ao segundo:É assim que fica no nosso
IntList
:Novamente, vamos tentar escrever o redutor:
appendFold
é um catamorphism paraappendReductor
que transformaIntList
emIntList
.Portanto, essencialmente, as álgebras F permitem definir 'dobras' em estruturas de dados recursivas, ou seja, operações que reduzem nossas estruturas a algum valor.
F-coalgebras
F-coalgebras são os chamados termos 'duplos' para álgebras F. Eles nos permitem definir
unfolds
tipos de dados recursivos, ou seja, uma maneira de construir estruturas recursivas a partir de algum valor.Suponha que você tenha o seguinte tipo:
Este é um fluxo infinito de números inteiros. Seu único construtor tem o seguinte tipo:
Ou, em termos de conjuntos
O Haskell permite padronizar a correspondência nos construtores de dados, para que você possa definir as seguintes funções trabalhando em
IntStream
s:Naturalmente, você pode 'unir' essas funções em uma única função do tipo
IntStream -> Int × IntStream
:Observe como o resultado da função coincide com a representação algébrica do nosso
IntStream
tipo. O mesmo pode ser feito para outros tipos de dados recursivos. Talvez você já tenha notado o padrão. Estou me referindo a uma família de funções do tipoOnde
T
está algum tipo. A partir de agora vamos definirAgora, F-coalgebra é um par
(T, g)
, ondeT
é um tipo eg
é uma função do tipog :: T -> F T
. Por exemplo,(IntStream, head&tail)
é um F1-coalgebra. Novamente, assim como nas álgebras F,g
eT
pode ser arbitrário, por exemplo,(String, h :: String -> Int x String)
também é uma álgebra F1 por alguns h.Entre todas as barras de carvão F, existem as chamadas barras de terminal F , que são duplas às álgebras F iniciais. Por exemplo,
IntStream
é um terminal F-coalgebra. Isso significa que, para todo tipoT
e funçãop :: T -> F1 T
, existe uma função chamada anamorfismo , que se converteT
emIntStream
, e essa função é única.Considere a seguinte função, que gera um fluxo de números inteiros sucessivos a partir do dado:
Agora vamos inspecionar uma função
natsBuilder :: Int -> F1 Int
, ou sejanatsBuilder :: Int -> Int × Int
:Novamente, podemos ver alguma semelhança entre
nats
enatsBuilder
. É muito semelhante à conexão que observamos anteriormente com redutores e dobras.nats
é um anamorfismo paranatsBuilder
.Outro exemplo, uma função que pega um valor e uma função e retorna um fluxo de aplicativos sucessivos da função para o valor:
Sua função de construtor é a seguinte:
Então
iterate
é um anamorfismo paraiterateBuilder
.Conclusão
Então, em resumo, as álgebras-F permitem definir dobras, isto é, operações que reduzem a estrutura recursiva em um único valor, e as álgebras-F permitem fazer o oposto: construir uma estrutura [potencialmente infinita] a partir de um único valor.
De fato, as álgebras F e as coalgebras de Haskell coincidem. Esta é uma propriedade muito agradável, que é uma conseqüência da presença do valor 'bottom' em cada tipo. Assim, em Haskell, podem ser criadas dobras e desdobramentos para todos os tipos recursivos. No entanto, o modelo teórico por trás disso é mais complexo do que o que apresentei acima, por isso evitei-o deliberadamente.
Espero que isto ajude.
fonte
appendReductor
aparência um pouco estranha e realmente não me ajudaram a ver o padrão lá ... :) Você pode verificar se está correto? .. Como devem ser os tipos redutores em geral? Na definição der
lá, éF1
determinado pelo IntList, ou é um F arbitrário?Percorrendo o artigo tutorial Um tutorial sobre (co) álgebras e (co) indução deve fornecer algumas dicas sobre co-álgebra em ciência da computação.
Abaixo está uma citação para convencê-lo,
Prelúdio, sobre a teoria das categorias. A teoria das categorias deve renomear a teoria dos functores. Como categorias são o que é preciso definir para definir functores. (Além disso, é necessário definir functores para definir transformações naturais.)
O que é um functor? É uma transformação de um conjunto para outro que preserva sua estrutura. (Para mais detalhes, há muitas boas descrições na rede).
O que é uma álgebra F? É a álgebra do functor. É apenas o estudo da propriedade universal do functor.
Como isso pode ser vinculado à ciência da computação? O programa pode ser visto como um conjunto estruturado de informações. A execução do programa corresponde à modificação desse conjunto estruturado de informações. Parece bom que a execução preserve a estrutura do programa. Então a execução pode ser vista como a aplicação de um functor sobre esse conjunto de informações. (Aquele que define o programa).
Por que F-co-álgebra? Os programas são duplos por essência, pois são descritos por informações e agem sobre ela. Então, principalmente as informações que compõem o programa e as modificam podem ser vistas de duas maneiras.
Então, nesta fase, eu gostaria de dizer isso,
Durante a vida de um programa, dados e estado coexistem, e eles se completam. Eles são duplos.
fonte
Começarei com coisas obviamente relacionadas à programação e depois adicionarei algumas coisas de matemática, para mantê-las tão concretas e práticas quanto possível.
Vamos citar alguns cientistas da computação sobre coindução ...
http://www.cs.umd.edu/~micinski/posts/2012-09-04-on-understanding-coinduction.html
http://adam.chlipala.net/cpdt/html/Coinductive.html
http://www.alexandrasilva.org/#/talks.html
Relacionando o Contexto Matemático Ambiental às Tarefas de Programação Habituais
O que é "uma álgebra"?
As estruturas algébricas geralmente se parecem com:
Isso deve soar como objetos com 1. propriedades e 2. métodos. Ou melhor ainda, deve parecer assinaturas de tipo.
Os exemplos matemáticos padrão incluem ⊃ grupo ⊃ espaço vetorial oid "uma álgebra". Monoides são como autômatos: sequências de verbos (por exemplo,
f.g.h.h.nothing.f.g.f
). Umgit
log que sempre adiciona histórico e nunca o exclui seria um monóide, mas não um grupo. Se você adiciona inversas (por exemplo, números negativos, frações, raízes, exclusão do histórico acumulado, quebra de um espelho quebrado), obtém um grupo.Grupos contêm itens que podem ser adicionados ou subtraídos juntos. Por exemplo,
Duration
s podem ser adicionados juntos. (MasDate
s não podem.) As durações residem em um espaço vetorial (não apenas em um grupo) porque também podem ser dimensionadas por números externos. (Uma assinatura de tipo descaling :: (Number,Duration) → Duration
.)Os espaços de vetor de álgebras podem fazer outra coisa: existem alguns
m :: (T,T) → T
. Chame isso de "multiplicação" ou não, porque uma vez que você saiIntegers
, é menos óbvio o que "multiplicação" (ou "exponenciação" ) deve ser.(É por isso que as pessoas buscam propriedades universais (teóricas das categorias): dizer a elas como a multiplicação deve fazer ou ser :
)
Álgebras → Coalgebras
A multiplicação é mais fácil de definir de uma maneira que parece não-arbitrária, do que a multiplicação, porque para passar,
T → (T,T)
basta repetir o mesmo elemento. ("mapa diagonal" - como matrizes / operadores diagonais na teoria espectral)O aconselhamento é geralmente o rastreamento (soma das entradas diagonais), embora, novamente, o importante seja o que o seu aconselhamento faz ;
trace
é apenas uma boa resposta para matrizes.A razão para olhar para um espaço duplo , em geral, é porque é mais fácil pensar nesse espaço. Por exemplo, às vezes é mais fácil pensar em um vetor normal do que no plano normal, mas você pode controlar aviões (incluindo hiperplanos) com vetores (e agora estou falando do vetor geométrico familiar, como em um traçador de raios) .
Domando (des) dados estruturados
Os matemáticos podem estar modelando algo divertido como o TQFT , enquanto os programadores precisam lutar com
+ :: (Date,Duration) → Date
),Paris
≠(+48.8567,+2.3508)
! É uma forma, não um ponto.),Os cientistas da computação, ao falarem sobre barras de carvão, geralmente têm em mente operações como o produto cartesiano. Eu acredito que é isso que as pessoas querem dizer quando dizem "Álgebras são barras de carvão em Haskell". Mas, na medida em que os programadores precisam modelar tipos de dados complexos como
Place
,Date/Time
eCustomer
- e fazer com que esses modelos se pareçam tanto com o mundo real (ou pelo menos com a visão do mundo real do usuário final) quanto possível - acredito que os duplos, poderia ser útil além do mundo do cenário.fonte