37 votes

Pourquoi avons-nous besoin de conteneurs?

(Comme une excuse: le titre imite le titre de Pourquoi avons-nous besoin de monades?)

Il y a des conteneurs (et indexé ceux) (et hasochistic ) et des descriptions. Mais les conteneurs sont problématiques et à ma très petite expérience, il est plus difficile de penser en termes de conteneurs qu'en termes de descriptions. Le type de non-indexé conteneurs est isomorphe a' Σ - c'est trop imprécise. Les formes et les positions description de l'aide, mais dans

⟦_⟧ᶜ : ∀ {α β γ} -> Container α β -> Set γ -> Set (α ⊔ β ⊔ γ)
⟦ Sh ◃ Pos ⟧ᶜ A = ∃ λ sh -> Pos sh -> A

Kᶜ : ∀ {α β} -> Set α -> Container α β
Kᶜ A = A ◃ const (Lift ⊥)

nous sommes essentiellement à l'aide de Σ plutôt que de la forme et de la position.

Le type de strictement positif gratuit monades plus de conteneurs est plutôt une définition simple, mais le type d' Freer monades semble plus simple pour moi (et dans un sens, Freer monades sont encore mieux que d'habitude Free monades comme décrit dans le papier).

Alors, que pouvons-nous faire avec les conteneurs dans une jolie manière qu'avec les descriptions ou quoi que ce soit d'autre?

27voto

pigworker Points 20324

À mon avis, la valeur de conteneurs (comme dans le conteneur de la théorie) est leur homogénéité. Que l'uniformité donne des possibilités considérables d'utilisation contenant des représentations que la base de spécifications exécutables, et peut-être même assisté par ordinateur programme de dérivation.

Conteneurs: un outil théorique, pas un bon moment de l'exécution de la représentation des données stratégie

Je ne recommande fixpoints de (normalisée) des conteneurs à un but d'intérêt général de façon à mettre en œuvre des structures de données récursives. C'est, il est utile de savoir qu'un foncteur a (jusqu'à iso) une présentation sous la forme d'un conteneur, car il indique que le conteneur générique fonctionnalité (qui est facilement mis en œuvre, une fois pour toutes, grâce à l'uniformité) peut être instancié à votre foncteur, et ce comportement vous devriez vous attendre. Mais cela ne veut pas dire qu'un conteneur de mise en œuvre sera efficace dans une manière pratique. En effet, je préfère généralement de premier ordre encodages (tags et les tuples, plutôt que des fonctions) de premier ordre des données.

Pour fixer la terminologie, nous disons que le type Cont de conteneurs (sur Set, mais d'autres catégories sont disponibles) est donnée par un constructeur <| d'emballage de deux champs, de formes et de positions

S : Set
P : S -> Set

(C'est la même signature de données qui est utilisée pour déterminer un Sigma type ou d'un type de Pi, ou un W type, mais cela ne signifie pas que les conteneurs sont les mêmes que pour l'une de ces choses, ou que ces choses sont les mêmes que les uns les autres.)

L'interprétation d'une telle chose comme un foncteur est donnée par

[_]C : Cont -> Set -> Set
[ S <| P ]C X = Sg S \ s -> P s -> X  -- I'd prefer (s : S) * (P s -> X)
mapC : (C : Cont){X Y : Set} -> (X -> Y) -> [ C ]C X -> [ C ]C Y
mapC (S <| P) f (s , k) = (s , f o k)  -- o is composition

Et nous sommes déjà à gagner. C'est map mis en œuvre une fois pour toutes. De plus, le foncteur lois tenir par le calcul seul. Il n'est pas nécessaire pour la récursivité sur la structure des types de construction de l'opération, ou pour prouver que les lois.

Les Descriptions sont dénormalisée conteneurs

Personne n'est d'essayer de prétendre que, du point de vue opérationnel, Nat <| Fin donne une efficace mise en œuvre de la liste, c'est qu'en faisant cette identification nous apprendre quelque chose d'utile sur la structure de listes.

Permettez-moi de dire quelque chose à propos de descriptions. Pour le bénéfice des lecteurs paresseux, permettez-moi de les reconstruire.

data Desc : Set1 where
  var : Desc
  sg pi  : (A : Set)(D : A -> Desc) -> Desc
  one : Desc                    -- could be Pi with A = Zero
  _*_ : Desc -> Desc -> Desc    -- could be Pi with A = Bool

con : Set -> Desc   -- constant descriptions as singleton tuples
con A = sg A \ _ -> one

_+_ : Desc -> Desc -> Desc   -- disjoint sums by pairing with a tag
S + T = sg Two \ { true -> S ; false -> T }

Les valeurs en Desc de décrire les foncteurs dont fixpoints donner les types de données. Qui foncteurs décrivent-elles?

[_]D : Desc -> Set -> Set
[ var    ]D X = X
[ sg A D ]D X = Sg A \ a -> [ D a ]D X
[ pi A D ]D X = (a : A) -> [ D a ]D X
[ one    ]D X = One
[ D * D' ]D X = Sg ([ D ]D X) \ _ -> [ D' ]D X

mapD : (D : Desc){X Y : Set} -> (X -> Y) -> [ D ]D X -> [ D ]D Y
mapD var      f x        = f x
mapD (sg A D) f (a , d)  = (a , mapD (D a) f d)
mapD (pi A D) f g        = \ a -> mapD (D a) f (g a)
mapD one      f <>       = <>
mapD (D * D') f (d , d') = (mapD D f d , mapD D' f d')

Il est inévitable d'avoir à travailler par récurrence plus de descriptions, de sorte qu'il est plus difficile de travailler. Le foncteur de lois, trop, ne sont pas gratuits. Nous obtenons une meilleure représentation des données, sur le plan opérationnel, parce que nous n'avons pas besoin de recourir à fonctionnels codages lorsque le béton tuples fera. Mais nous devons travailler plus fort pour écrire des programmes.

Notez que chaque récipient a une description:

sg S \ s -> pi (P s) \ _ -> var

Mais il est également vrai que chaque description a une présentation comme une isomorphe conteneur.

ShD  : Desc -> Set
ShD D = [ D ]D One

PosD : (D : Desc) -> ShD D -> Set
PosD var      <>       = One
PosD (sg A D) (a , d)  = PosD (D a) d
PosD (pi A D) f        = Sg A \ a -> PosD (D a) (f a)
PosD one      <>       = Zero
PosD (D * D') (d , d') = PosD D d + PosD D' d'

ContD : Desc -> Cont
ContD D = ShD D <| PosD D

C'est-à-dire, les conteneurs sont une forme normale pour les descriptions. C'est un exercice pour montrer qu' [ D ]D X est naturellement isomorphe a' [ ContD D ]C X. Qui rend la vie plus facile, parce que dire que faire pour les descriptions, il suffit, en principe, de dire ce qu'il faut faire pour leurs formes normales, les conteneurs. Le ci-dessus mapD opération pourrait, en principe, être obtenue par fusion de la isomorphisms à la définition uniforme de l' mapC.

Différentiel de structure: les conteneurs montrer le chemin

De même, si nous avons une notion de l'égalité, on peut dire ce qu'est un trou de contextes pour les conteneurs de manière uniforme

_-[_] : (X : Set) -> X -> Set
X -[ x ] = Sg X \ x' -> (x == x') -> Zero

dC : Cont -> Cont
dC (S <| P) = (Sg S P) <| (\ { (s , p) -> P s -[ p ] })

C'est le cas, la forme d'un trou de contexte dans un conteneur est la paire de la forme du contenant d'origine et de la position du trou; les positions sont des positions d'origine en dehors de celui du trou. C'est la preuve pertinents version de "multiplier par l'indice, décrémenter l'index" lors de la différenciation de puissance de la série.

Ce traitement uniforme nous donne la spécification à partir de laquelle on peut tirer des siècles de l'ancien programme pour calculer la dérivée d'un polynôme.

dD : Desc -> Desc
dD var = one
dD (sg A D) = sg A \ a -> dD (D a)
dD (pi A D) = sg A \ a -> (pi (A -[ a ]) \ { (a' , _) -> D a' }) * dD (D a)
dD one      = con Zero
dD (D * D') = (dD D * D') + (D * dD D')

Comment puis-je vérifier que mon dérivés de l'opérateur pour les descriptions sont correctes? Par le contrôle contre la dérivée de conteneurs!

Ne tombez pas dans le piège de penser que juste parce que une présentation d'une idée n'est pas utile sur le plan opérationnel qu'il ne peut pas être conceptuellement utile.

Sur la Libéralisation des monades

Une dernière chose. L' Freer astuce montants de réorganiser l'arbitraire d'un foncteur d'une manière particulière (commutation à Haskell)

data Obfuncscate f x where
  (:<) :: forall p. f p -> (p -> x) -> Obfuncscate f x

mais ce n'est pas une alternative à conteneurs. C'est une légère nourrissage d'un conteneur de présentation. Si nous avions une forte existentiels et des types dépendants, on pourrait écrire

data Obfuncscate f x where
  (:<) :: pi (s :: exists p. f p) -> (fst s -> x) -> Obfuncscate f x

de sorte qu' (exists p. f p) représente des formes (où vous pouvez choisir votre représentation de positions, puis les marque place avec sa position), et fst choisit les existentielle témoin d'une forme (la position de la représentation que vous avez choisi). Il a le mérite d'être bien évidemment strictement positif exactement parce que c'est une boite de présentation.

En Haskell, bien sûr, vous avez à curry les existentielle, qui, heureusement, laisse une dépendance seulement sur le type de projection. C'est la faiblesse de l'existentiel qui justifie l'équivalence des Obfuncscate f et f. Si vous essayez cette astuce dans un type dépendant de la théorie avec de fortes existentiels, l'encodage perd son caractère unique parce que vous pouvez le projet et de distinguer les différents choix de représentation pour les postes. C'est, je peut représenter Just 3 par

Just () :< const 3

ou par

Just True :< \ b -> if b then 3 else 5

et dans Coq, disons, ceux-ci sont sensiblement distinctes.

Défi: caractérisation des fonctions polymorphes

Chaque fonction polymorphe entre les types de conteneurs est donné d'une manière particulière. Il n'y a que l'uniformité de travail afin de clarifier notre compréhension de nouveau.

Si vous avez quelques

f : {X : Set} -> [ S <| T ]C X -> [ S' <| T' ]C X

il est (extensionally) données par les données suivantes, qui ne font aucune mention d'éléments que ce soit:

toS    : S -> S'
fromP  : (s : S) -> P' (toS s) -> P s

f (s , k) = (toS s , k o fromP s)

C'est la seule manière de définir une fonction polymorphe entre les conteneurs est-à-dire comment traduire entrée formes de sortie de formes, puis dire comment remplir les positions de sortie à partir des positions d'entrée.

Pour votre préférée à la représentation de foncteurs strictement positif, donner un de même serré la caractérisation des fonctions polymorphes, ce qui élimine l'abstraction sur le type de l'élément. (Pour les descriptions, je voudrais utiliser exactement leur reducability à conteneurs.)

Défi: la capture "transposabilité"

Étant donné deux foncteurs, f et g, il est facile de dire ce que leur composition f o g est: (f o g) x encapsule les choses en f (g x), nous donnant "f-structures d' g-structures". Mais pouvez-vous facilement imposer la condition supplémentaire que l'ensemble de l' g des structures stockées dans l' f de la structure ont la même forme?

Disons qu' f >< g des captures de la transposables fragment d' f o g, où tous les g des formes sont les mêmes, de sorte qu'on peut tout aussi bien tourner la chose dans un g-structure de l' f-structures. E. g., alors qu' [] o [] donne lambeaux de listes de listes, [] >< [] donne rectangulaire de matrices, [] >< Maybe propose des listes qui sont soit toutes Nothing ou tous Just.

Donnez >< pour votre préférée à la représentation de foncteurs strictement positif. Pour les conteneurs, c'est facile.

(S <| P) >< (S' <| P') = (S * S') <| \ { (s , s') -> P s * P' s' }

Conclusion

Les conteneurs, en leur normalisé Sigma-puis-Pi formulaire ne sont pas destinés à être une machine efficace de représentation de données. Mais la connaissance qu'un foncteur, mis en œuvre, cependant, a une présentation sous la forme d'un conteneur, nous aide à comprendre sa structure et lui donner l'équipement utile. De nombreuses constructions peuvent être donnés de façon abstraite pour les conteneurs, une fois pour toutes, quand elles doivent être données au cas par cas pour d'autres présentations. Donc, oui, c'est une bonne idée d'en apprendre sur les conteneurs, si ce n'est à saisir les raisons de la plus de des constructions spécifiques vous réellement mettre en œuvre.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X