Pourquoi les constructeurs de données portant le même nom sont-ils interdits dans différents constructeurs de types?

11

La déclaration suivante donne une erreur:

type Vec2d = (Float, Float)
type Vec3d = (Float, Float, Float)
-- Rect x y defines a rectangle spanning from (0,0) to (x,y)
data Obj2d = Rect Float Float
           | Translate Vec2d Obj2d
-- Cuboid x y z defines a cuboid spanning from (0,0,0) to (x,y,z)
data Obj3d = Cuboid Float Float Float
           | Translate Vec3d Obj3d

à savoir Multiple declarations of 'Translate'.

Maintenant, je me demande pourquoi cette limitation a été introduite?

Si la limitation n'était pas là, on pourrait écrire

Translate (1, 1) Rect 2 2 et Translate (1, 2, 3) Cuboid 1 1 1, ce qui semble naturel.

Je ne vois pas (immédiatement) comment cela pourrait entraîner un problème d'analyse pour interdire d'utiliser le même nom, le type pourrait être déduit par l'argument ( Rect 2 2est un Obj2d, Cuboid 1 1 1est un Obj3d).

Je suis sûr qu'il y a une bonne raison pour laquelle les concepteurs de langage ont choisi de ne pas utiliser le même nom pour les constructeurs de données de différents types, mais j'aimerais savoir: pourquoi, quand ce n'est pas évidemment nécessaire?

(Et la désambiguïsation de type est l'affaire du pain et du beurre de Haskell!)

A Sz
la source
3
Concernant le type déduit par l'argument: Savez-vous que parfois le type de l' argument est déduit du type de la fonction ?
@delnan Je n'étais pas au courant de ça ... ça ressemble à une réponse pour moi. J'avais toujours pensé que l'inférence était ascendante, même si je pouvais voir la résolution de l'ambiguïté en utilisant les informations de type de l'autre côté du graphique de type comme vous le décrivez comme facteur décisif ... mon image mentale pour cela est les types de retour au bas de la appels graphique et fonction en haut, la résolution est un agrégat formé par pliage du fond, mais c'est pas tout à fait toute l' image, est ce que vous dites? Sans surprise, dans une langue typiquement dépendante avec une inférence parfaite, c'est probablement plus précis ..
Jimmy Hoffa

Réponses:

13

En effet, les constructeurs de données ne sont que des fonctions et la surcharge de fonctions n'est pas autorisée dans Haskell. Il pourrait être plus clair si vous utilisez la syntaxe GADT pour définir vos types:

{-# LANGUAGE GADTs #-}
data Obj2d where
    Rect :: Float -> Float -> Obj2d   -- a function from floats to obj2d's
    Translate :: Vec2d -> Obj2d       -- a function from vec2d's to Obj2d's

Je pense qu'ils (les développeurs du GHC) travaillent sur des solutions possibles à ce problème en introduisant un nouveau type classpour tous les types qui partagent le même constructeur de données, ou quelque chose de similaire. Alors restez à l'écoute, une solution à votre problème pourrait bientôt arriver! (J'espère)

bstamour
la source
Je suis vraiment impatient de ces type classconstructions que vous stipulez. - La raison en est: je n'ai pas de problème, je peux le faire Translate2et Translate3d, mais je préfère ne pas polluer l'espace de noms.
Un Sz
Je ne suis pas un développeur du GHC, donc c'est juste de l'écoute. J'espère que ça arrive aussi.
bstamour