2016-08-01 2 views
0

J'ai travaillé sur la construction de mon propre simulateur Diplomacy dans Haskell pour me mouiller les pieds.Types/Types Confusion dans Haskell (peut-être) dans les types de données algébriques

Je crois que je suis venu avec une définition convenable pour quel ordre est:

data Order = Hold Unit Territory 
      | Move Unit Territory Territory 
      | Support Unit Territory Unit Territory Territory 
      | Convoy Fleet Territory Army Territory Territory 
    deriving (Eq, Show) 

Pour ceux qui ne connaissent pas le jeu, les commandes sont écrites sous la forme de « Hold flotte London », "Move Fleet London Canal anglais", "Flotte de soutien flotte de la Manche de l'Atlantique Nord Atlantique Nord" ou "Convoi Flotte de la Manche de l'armée anglaise Londres Brest", etc

Maintenant, avec la définition de l'unité comme data Unit = Fleet | Army (deriving Eq, Show), I ' Je reçois l'erreur Not in scope: type constructor or class 'Fleet' en ce qui concerne ma définition de l'ordre.

Pourquoi est-ce? Comment puis-je écrire mes définitions d'unités ou d'ordres (ou devrais-je faire quelque chose de différent) qui me permet d'exiger que le premier argument de Convoy soit une flotte et le troisième argument soit une armée? Est-ce que je ne suis pas "faux" avec mon approche de ce problème? Dois-je aborder cela dans ma fonction de validation (parce qu'il n'y a pas moyen de spécifier uniquement des commandes valides via Haskell, pour autant que je sache, c'est expressif mais pas si expressif)? J'ai déjà essayé d'utiliser "DataKinds", mais cela ne m'a pas aidé du tout (malgré le post-scriptum d'erreur suggérant de le faire, alors encore une fois, les postscript de l'erreur Haskell suggèrent beaucoup de choses, donc je doute que je doive payer trop y prêter attention).

+0

Je suis un peu confus avec la terminologie. Vous montrez votre erreur lors de l'utilisation des types de données, mais demandez ensuite comment faire Fleet dans une classe de type? De toute façon, vous obtenez l'erreur car 'Fleet' n'est pas un type, c'est un constructeur du type' Unit'. Je pense que vous devriez repenser votre conception un peu. De plus, 'DataKinds' n'est certainement pas ce que vous voulez. Ils sont une fonctionnalité avancée qui ne s'applique pas ici. – pdexter

+0

Oh, je ... j'ai un peu oublié que j'avais dit ça. Merci pour ça. Mise à jour maintenant fixé ceci. –

Répondre

4
data Unit = Fleet | Army 

Unit est un type. Ses valeurs peuvent être Fleet ou Army - ce ne sont pas des types.

data Order = Hold Unit Territory 
      | Move Unit Territory Territory 
      | Support Unit Territory Unit Territory Territory 
        ^^^^   ^^^^ 

Ce sont des types - OK.

  | Convoy Fleet Territory Army Territory Territory 
        ^^^^^   ^^^^ 

Ce sont des valeurs - pas OK. La ligne ci-dessus est assez similaire à

  | Convoy "hello" Territory 42 Territory Territory 

ce qui n'a aucun sens.

Vous pourriez simplement vouloir utiliser

  | Convoy Territory Territory Territory 

mais je ne suis pas familier avec le jeu, donc je ne sais pas ce que vous avez réellement besoin là-bas.

Aussi, oubliez avec les typeclasses et l'extension DataKinds - n'utilisez pas les trucs avancés sauf si vous en avez vraiment besoin.


Comme une autre option, si vous avez l'intention d'ajouter des champs à Fleet et Army, est de les transformer en types

data Fleet = F String Int -- dummy fields, you can put none 
data Army = A 
data Unit = FleetUnit Fleet | ArmyUnit Army -- added the types here 
data Order = Hold Unit Territory 
      | Move Unit Territory Territory 
      | Support Unit Territory Unit Territory Territory 
      | Convoy Fleet Territory Army Territory Territory 

Maintenant, la dernière ligne est ok. Le prix pour cela est que vous devez utiliser plus de constructeurs "wrapping" pour construire une commande, par ex.

orderExample1 :: Order 
orderExample1 = Convoy (F "test" 33) terr1 A terr2 terr3 

orderExample2 :: Order 
orderExample2 = Support (FleetUnit (F "test2" 55)) terr1 (ArmyUnit A) terr2 terr3 

Au-dessus, F ... construit un Fleet, puis FleetUnit ... il se transforme en un Unit, et enfin Support ... tourne que dans un Order.

+0

Je viens d'éditer mon post pour clarifier un peu plus à ce sujet. A en juger par cela, je pense que je vais juste aller la route de la fonction de validation (lire la modification). De plus, je ne savais pas que typeclasses et DataKinds étaient avancés (je ne sais même pas ce qui est avancé avec cette langue ... il m'a fallu deux jours entiers pour essayer de comprendre ce que tout l'arithmétique de Peano avec (+) étant défini en termes de Succ ... oy vey), je les ai vus partout dans les écrans d'erreur. –

+1

Je suppose que la question principale est: est-ce que 'Fleet' et' Army' ont des champs? Comme indiqué ci-dessus, ils ne portent aucune information avec eux. Si tel est le cas, quel serait le gain en passant un argument 'Fleet' à' Convoy', si vous savez déjà que c'est la seule valeur que cet argument peut avoir? – chi

+0

À l'heure actuelle, ils n'ont pas de champs, mais je peux changer cela. Je ne peux pas décider si oui ou non je veux un Territoire donné (fondamentalement un emplacement, donc la Manche anglaise serait un Territoire) à Peut-être avoir une Unité associée ou si je veux qu'une Unité soit associée à un Territoire. J'espérais être capable de faire quelque chose comme être capable d'écrire 'Convoy (éliminer $ unit unTerritory) unTerritory otherTerritory' ou quelque chose du genre (où eliminer supprime juste le Just from a Maybe ou jette une erreur –