2017-09-28 5 views
2

Ce que j'essaie de construire est un arbre générique de syntaxe abstraite. Je suppose que j'ai un ensemble fixe de constructions syntaxiques et je définis un type F # pour chacun d'eux. Cependant, la représentation de par ex. Les noms d'identificateurs et les expressions doivent rester ouverts (génériques). Ainsi, le code ressemblera à quelque chose comme:Ce problème avec les modules (non) génériques en F #, encore

module GAST = 
    type Declaration<'Name, 'Expr> = 
    { 
     id: 'Name 
     initialValue: 'Expr 
    } 

    type Loop<'Name, 'Expr> = 
    { 
     condition: 'Expr 
     body: Statement<'Name, 'Expr> list 
    } 

    and Statement<'Name, 'Expr> = 
    | Declaration of Declaration<'Name, 'Expr> 
    ... 
    | Loop of Loop<'Name, 'Expr> 
    ... 

Vous voyez le problème: j'ai beaucoup de types, tous paramétrés par 'Name et 'Expr. Quand je veux « instancier » mon AST générique à un AST spécifique que je devrais écrire un nouveau module où j'instancier chaque type individuel:

module SpecificAST = 
    type Name = string 
    type Expr = | Name of Name | Const of int | Addition of Expr * Expr 

    type Declaration = GAST.Declaration<Name, Expr> 
    type Loop = GAST.Loop<Name, Expr> 
    type Statement = GAST.Statement<Name, Expr> 

Cela semble comme beaucoup de duplication de code, et crie quelque chose comme un module que vous pourriez passer des types comme arguments, parce que je veux vraiment quelque chose comme

module SpecificAST = GAST<Name, Expr> 

ce qui précède n'est pas possible en F #. Lors de la recherche, j'ai trouvé Is it possible to pass parameters to F# modules? mais là le problème est différent. Il y a seulement une définition de type mais le comportement des fonctions de ce type est paramétré qui peut être résolu en transformant le type d'enregistrement en classe et en passant le comportement comme argument lors de l'instanciation.

J'ai aussi vu Can ML functors be fully encoded in .NET (C#/F#)? mais je ne voyais pas comment les différents liens pouvaient m'aider. Donc, ma question est la suivante: Étant donné plusieurs types génériques avec les mêmes paramètres de type. Puis-je instancier tout en même temps mais éviter une mauvaise duplication de code dans le module d'instanciation?

Répondre

2

Je pense que la solution que vous avez est la meilleure que vous pouvez faire avec F # en utilisant votre façon actuelle de structurer le problème - F # n'a pas de foncteurs ML et il n'y a pas de façon universelle de les simuler. Cela dit, je ne serais pas surpris s'il y avait une autre façon de structurer le problème qui vous permettrait de le résoudre d'une manière plus agréable. Votre exemple minimal est assez bon pour voir que vous ne pouvez pas simuler ML foncteurs avec F #, mais il ne donne pas assez de détails pour les solutions alternatives:

  • Combien de RSHS spécifiques vous envisagez de construire? Votre exemple n'en a qu'un seul, mais même si vous en aviez trois, il pourrait être plus facile de simplement dupliquer le code plutôt que d'introduire des abstractions qui ne vous laisseront pas réutiliser beaucoup.

  • Que voulez-vous faire avec les types partagés? Y a-t-il des fonctions qui fonctionneront pour tous les AST en béton? Il y a peut-être une autre façon de réutiliser cette fonctionnalité sans avoir de foncteurs de style ML.

Alors, je pense que la réponse à votre question est que votre solution est le meilleur que vous pouvez faire, mais si vous avez fourni plus d'informations sur la motivation pour elle, il pourrait y avoir une conception plus belle F #.

+0

L'implémentation actuelle comporte deux arborescences, non typées et typées. Ils ont la même structure mais diffèrent dans la représentation des noms, des types et des expressions (langage source). Ils ont tous les deux des marcheurs (avant et après l'ordre) qui traversent la structure arborescente en exécutant certaines actions données. La question qui se posait était de savoir si les parties communes - la structure et ses marcheurs - pouvaient être unifiées.Ensuite, les arbres non typés et typés seraient simplement des instances du même AST avec des implémentations différentes pour les noms, les types et les expressions (langage source). D'où le design proposé. –

+0

Bien sûr, la conception n'est pas la meilleure solution de toute façon, car je voudrais éventuellement jouer avec l'interface du serveur de langue des éditeurs. Pour cela, des parties des arbres devraient être recalculées en temps réel, ce qui nécessite probablement une configuration complètement différente. –