13

Comment Haskell résoudre le problème « structure de données normalisée immuable »?modèle de données Normalisé et immuable

Par exemple, considérons une structure de données représentant les ex petites amies/petits amis:

data Man = Man {name ::String, exes::[Woman]} 

data Woman = Woman {name :: String, exes::[Man]} 

Qu'advient-il si une femme change son nom et elle avait été avec 13 l'homme? Alors tout l'homme devrait être "mis à jour" (au sens de Haskell) aussi? Une sorte de normalisation est nécessaire pour éviter ces "mises à jour".

Ceci est un exemple très simple, mais imaginez un modèle avec 20 entités et les relations arbitraires entre eux, quoi faire alors?

Quelle est la méthode recommandée pour représenter des données complexes, normalisées dans une langue immuable?

Par exemple, une solution Scala se trouvent here (voir code ci-dessous), et il utilise des références. Que faire à Haskell?

class RefTo[V](val target: ModelRO[V], val updated: V => AnyRef) { 
    def apply() = target() 
} 

Je me demande, si des solutions plus générales comme celle-ci (en Scala) ne fonctionnent pas dans Haskell ou ils ne sont pas nécessaires? Si elles ne fonctionnent pas, alors pourquoi pas? J'ai essayé de chercher des bibliothèques qui le font dans Haskell mais elles ne semblent pas exister. En d'autres termes, si je veux modéliser une base de données SQL normalisée dans Haskell (par exemple pour être utilisé avec acid-state) existe-t-il un moyen général de décrire les clés étrangères? En général, je veux dire, ne pas coder à la main les identifiants comme suggéré par chepner dans les commentaires ci-dessous.

EDIT:

Pourtant, autrement dit, est-il une bibliothèque (pour Haskell ou Scala) qui implémente une base de données SQL/relationnelle en mémoire (éventuellement en utilisant l'approvisionnement de l'événement pour la persistance) de telle sorte que la base de données est immuable et la plupart des opérations SQL (query/join/insert/delete/etc.) sont implémentées et sont sécurisées. S'il n'y a pas une telle bibliothèque, pourquoi pas? Cela semble être une très bonne idée. Comment devrais-je créer une telle bibliothèque?

EDIT 2:

Quelques liens connexes:

+6

Si vous aviez des données normalisées, auriez-vous pas 'data Man = Man {nom :: String, exes :: [WomanID]}', où 'womanID' était un index dans une histoire de structure de données' valeurs Woman' (quelque chose comme 'Map WomanID Woman'?) Si vous changez le nom d'une valeur' Woman', ceci n'affecte pas la valeur de 'Man' qui la référence, vous avez seulement besoin de mettre à jour la valeur unique dans' Map' – chepner

+0

l'exemple donné n'est pas normalisé La question est de savoir s'il existe une solution générale pour créer des structures de données normalisées (quelque chose qui s'occupe de la gestion des identifiants, etc.) Je veux dire, que font les Haskeller lorsqu'ils veulent créer des données normalisées? Doivent-ils toujours coder à la main les identifiants? Ou y a-t-il déjà une solution plus générale à ce problème? Ce que vous avez proposé est un exemple de codage à la main des ID, mais cela pourrait être automatisé. résol ving ces ID. – jhegedus

+2

@jhegedus La question en l'état est un peu large - cela dépend vraiment de la situation. Si vous mettez constamment à jour les hommes et les femmes, vous pouvez effectuer le calcul dans une monade d'état (l'état étant la table/carte des hommes/femmes). Si vous cherchez une approche fonctionnelle pour des structures de graphes plus générales, consultez ['fgl'] (https://hackage.haskell.org/package/fgl). En ce qui concerne les IDs: il y a des situations où vous pouvez [attacher le noeud] (https://wiki.haskell.org/Tying_the_Knot) (parfois même en utilisant le 'Map'), mais en général vous devrez peut-être donner des ID de code . – Alec

Répondre

9

Le problème est que vous stockez des données et des relations dans le même type. Pour normaliser, vous devez séparer. Bases de données relationnelles 101.

newtype Id a = Id Int -- Type-safe ID. 
data Person = Person { id :: Id Person, name :: String } 
data Ex = Ex { personId :: Id Person, exId :: Id Person } 

Maintenant, si une personne change son nom, une seule valeur Person est affectée. Les entrées Ex ne se soucient pas des noms des peuples.

+1

Point intéressant! C'est une relation de plusieurs à plusieurs, en effet. Cependant, comme je l'ai déjà mentionné dans la question, ce que je voulais dire, c'est «ne pas coder à la main les pièces d'identité, comme le suggère Chepner dans les commentaires ci-dessous». Une sorte de bibliothèque qui fait ce que vous avez suggéré mais enlève tout le passe-partout et ajoute le support pour les requêtes, les jointures et autres joyeusetés.Fondamentalement une base de données SQL, mais au lieu d'utiliser SQL comme un langage de requête, il utilise Haskell pour décrire les choses qui peuvent être décrites avec SQL. Tapez sûr et immuable. – jhegedus

+0

@jhegedus Voici la chose. Vous ne pouvez pas faire abstraction de la clé étrangère; cela fait partie de la sémantique de votre domaine - c'est-à-dire, il répond à la question «Qu'est-ce qui rend unique une personne dans la relation? Aucune bibliothèque ne peut décider cela pour vous. – Yawar

+0

Donc, fondamentalement 'Ex' correspond à une table de base de données SQL qui doit être explicitement spécifiée. Je comprends cela, mais peut-être que SQL peut être remplacé par Haskell, tapez entièrement safe, immutable. Ou pas ? Je me demande pourquoi cela n'a pas été fait? (Pas une liaison à une base de données, mais une base de données en mémoire réelle, écrit dans Haskell). Je demande ceci parce qu'un ami écrit une application (réussie) dans Scala, et fait exactement cela parce que 1) aucune duplication de données (mémoire-base de données), 2) type sécurité 3) Scala est plus expressif que SQL. Donc, si cela vaut la peine de le faire dans Scala, pourquoi pas Haskell lib. existe pour cela? Je me demande – jhegedus

0

Le projet M63 vient plutôt close à ce que je cherchais. Il est écrit en Haskell.

Une solution Haskell plus légère est décrite dans le poste de Gabriel Gonzalez "A very general API for relational joins".

+0

Pouvez-vous donner un exemple de la façon dont vous appliqueriez le projet M63 spécifiquement au modèle dont vous avez parlé? En outre, le lien avec le texte «fermer» semble être un message dans votre boîte de réception personnelle Gmail. La technique de jointure de Gabriel Gonzalez est sacrément cool - mais elle ne résout toujours pas la gestion des ID – Yawar

+0

Merci, j'ai corrigé le lien. – jhegedus

+0

Je ne sais pas comment utiliser M36, basé sur la description mais il semble que ce soit ce que je cherchais. Base de données relationnelle immuable. Il semble pour l'instant qu'il n'y ait pas d'équivalent Scala (du moins pas public). Ou peut-être que je ne le sais pas? Il serait intéressant de savoir s'il y a quelque chose comme M36 pour Scala. – jhegedus