2010-03-12 5 views
0

J'essaie de comprendre les modèles de types et les classes génériques dans Haskell, mais je n'arrive pas à l'obtenir.Motifs de type et classes génériques dans Haskell

Quelqu'un pourrait-il expliquer en termes simples?

Dans [1] J'ai lu que

« Appliquer des fonctions génériquement à tous les types de données, nous considérons les types de données de manière uniforme: à l'exception des types prédéfinis de base tels que Float, IO, et →, chaque type de données Haskell peut être considéré comme une somme étiquetée de produits éventuellement étiquetés. "

puis Unit, :*: et :+: sont mentionnés. Tous les types de données dans Haskell sont-ils automatiquement des versions de ce qui est mentionné ci-dessus et si oui, comment puis-je comprendre comment un type de données spécifique est représenté en termes de :*:, etc? Le guide de l'utilisateur pour les classes génériques (chapitre 7.16) sur haskell.org ne mentionne pas les types prédéfinis, mais ne devrait-il pas être traité dans chaque fonction si les modèles de type doivent être exhaustifs?

[1] Comparaison des approches de programmation générique dans Haskell, Ralf Hinze, Johan Jeuring et Andres Löh

Répondre

4

Ils font cela en main. C'est analogue à la forme "somme des produits" utilisée dans l'algèbre booléenne. Puisque chaque type de données algébrique est construit à partir de sommes et de produits, la transformation est probablement assez similaire à celle de l'algèbre booléenne, seulement dans ce cas ils extraient la structure et rejettent une partie de la sémantique.

Leur exemple est List a, d'abord défini comme

data List a = Nil | Cons a (List a) 

mais Transformé en

data List a = Unit :+: (a :*: (List a)). 

je viens juste effleuré le papier, mais je peux voir la valeur à extraire les constructeurs de type d'un déclaration et la construction de tout sur + et * opérateurs. Avant d'utiliser ces types de structure plus génériques, ils définissent un isomorphisme pour montrer qu'ils sont en fait les mêmes. Ils comprennent également des étiquettes avec le nom des dossiers et des constructeurs, que je vais partir au large:

from Nil = Unit 
from (Cons x y) = x :*: y 
to Unit = Nil 
to (x :*: y) = Cons x y 
+0

OK. Donc j'ai besoin de tout définir en termes de ': +:' & c si je veux utiliser des classes génériques, mais qu'est-ce que '{| ... |} (...) '? Je comprends que c'est des cas mais je ne comprends pas quels cas j'ai eu. Je pense que je comprends '{| a: +: b |} (Inr y) 'et' {| Unit |} Unit' mais je ne comprends pas '{| a: +: b |} (1: b) 'et' {| Unité |} bs'. Deux autres questions: est-ce que tout le pattern ne correspondrait pas à la rupture de List si je commençais à redéfinir 'List' et est-il même possible de redéfinir les types de données? – finnsson

1

D'accord, vous ne pouvez aimer entendre cela, mais vous devez l'entendre. Ceci est un document de recherche. Ce n'est pas un manuel d'instruction ou une feuille de triche sur la façon de le faire. Ceci est une exploration spécifique de la façon de le faire sous une nouvelle forme qui utilise ce que Haskell vous donne déjà (c'est-à-dire, ce n'est pas une bibliothèque standard ... encore ... c'est une façon d'en faire une, donc pas besoin pour le refaire plus tard). C'est comme quand vous écrivez du code pour faire une pile ou une file d'attente - c'est un exercice. Si vous pouvez l'utiliser pour quelque chose de réel, alors plus de pouvoir pour vous, mais en général, c'est une illustration ou ce que vous pourriez faire dans la langue, pas une instruction pour la façon dont vous êtes censé le faire.Cela ne veut pas dire que le papier n'est qu'un exercice de jouet et ne pourrait jamais être utilisé pour quelque chose d'important, mais simplement pour montrer comment vous pouvez organiser votre programme de sorte que vous n'écriviez pas autant de choses. ou vous répéter sans économies d'effort. En ce qui concerne {| ... |} (...), c'est la façon dont les auteurs parlent d'un type et d'une valeur de ce type. Plus précisément, le {|...|} est un moyen pour les auteurs de représenter un type en tant que valeur. C'est juste de l'ondulation suspendue, de l'incrédulité, de la pensée, de l'expérimentation. C'est une manière sophistiquée de jouer "Let's Pretend". Les auteurs disent: «Regardez, Haskell ne nous permet pas vraiment de passer un type à une fonction, donc nous allons utiliser cette forme comme un raccourci pour dire:« Souvenez-vous de cette section entière que nous venons de traverser. montrer comment obtenir une représentation d'un type avec tous les types Con (structor) et Label? Eh bien, prétendre que nous avons fait cela, et le résultat pour un certain type a est ce que nous entendons par {|a|}. "C'est une notation pour montrer que la fonction (encoder, décoder, mapper, showP, et al.) Obtient, et en utilisant, le le type, ainsi que la valeur, de quelque terme

Quant à vos questions.

  1. ne seraient pas toutes ltrage sur List de pause si je commence à redéfinir List Si? vous le redéfinissez d'une manière qui ne correspond plus à sa définition "actuelle", alors bien sûr, il le ferait! (Indice: c'est le point du formulaire {|...|}: votre fonction sait de quel type vous jouez, donc elle sait comment jouer avec elle aussi! ;)

  2. Est-il même possible de redéfinir les types de données ? Bien sûr que oui! (Je me sens comme le répondeur #haskell @FAQ, ici ...) Voir l'indice, ci-dessus. :)

J'espère que cela répond à votre question. Si vous avez d'autres questions, ou si vous voulez le faire avec un être humain vivant, vous pouvez toujours passer par le canal IRC sur freenode (juste au cas où vous ne saviez pas pourquoi j'ai mis cette marque de hachage et le signe 'at' dans le phrase ci-dessus). Des gens très sympathiques et serviables, frustrant pour les trolls partout! :)

Questions connexes