1

Im essayant de créer un analyseur pour une petite langue avec les commandes, y compris les étiquettes et goto:Ajout d'une étiquette à des classes de cas immuables dans Scala

... 
lazy val cmds = opt("{")~>rep(cmd<~opt(";"))<~opt("}") ^^ {...} 
lazy val cmd = ("if"~boolexpr~"then"~cmds~"else"~cmds 
    ^^ { case _~b~_~c1~_~c2 => IFCMD(boolexpr,c1 
| ident ~":="~numericLit ^^ {case i1~_~v => ASSIGN(i1,v) } 
| "goto" ~>ident ^^ { case l => GOTO(l) } 
| ident~":"~cmd ^^ { case l~_~c => <APPENDLABELTO_CORE> 
... 

le GOTO, IFCMD etc sont des classes de cas s'étendant classe abstraite Core

Conformément à la fonctionnelle/scala-comme/immuable-objecty -Way Je pense que la définition Core comme celui-ci est mal:

abstract class Core(var label:Option[String] = None) 

mais me permettrait de remplacer la pièce avec <APPENDLABELTO_CORE> avec: chemin

| ident~":"~cmd ^^ { case l~_~c => c.label = Some(l); c } 

Quelqu'un peut-il indiquer le « scalaish » pour le faire?

(je l'ai essayé c copy (label=Some(l)) mais la classe de base abstraite n'a pas la magie automatique constructeur de copie)

Répondre

4

Il est tout à fait possible de créer votre propre méthode semblable copie:

abstract class Core(val label: Option[String]) { 
    def set(label: Option[String]): Core 
} 
class Impl(label: Option[String] = None) extends Core(label) { 
    def set(label: Option[String] = this.label) = new Impl(label) 
} 

utilisé thusly:

scala> val i = new Impl 
i: Impl = [email protected] 

scala> i.label 
res0: Option[String] = None 

scala> i.set(label = Some("thing")) 
res1: Impl = [email protected] 

scala> res1.label 
res2: Option[String] = Some(thing) 

Mais, de façon pragmatique, je ne serais pas trop prompts à rejeter l'utilisation de vars ici. Il est plus facile de raisonner sur des valeurs immuables, mais celles que vous obtenez sont assez bien isolées dans l'analyseur, pour autant que je sache. Une autre idée serait de créer une méthode qui convertisse tout à une version immuable à la fin, ou si le code de l'analyseur finit par stocker toutes les données ailleurs, tout en le laissant mutable.

Une autre façon de faire est de rendre la classe abstraite non abstraite, mais de la transformer en classe de casse. Vous pouvez dériver des classes à partir d'une classe de cas (la dérivation de classes de cas à partir de classes de cas est un non-non, cependant). L'astuce serait alors de rendre vos données variables que vous devrez peut-être conserver en direct dans un champ:

abstract class SpecializedStuff { } 
case class ParticularStuff(val i: Int) extends SpecializedStuff 
case class Core(details: SpecializedStuff, label: Option[String] = None) 
class Impl(p: ParticularStuff) extends Core(p) 

scala> val i = new Impl(ParticularStuff(5)) 
i: Impl = Core(ParticularStuff(5),None) 

scala> i.copy(label = Some("thing")) 
res0: Core = Core(ParticularStuff(5),Some(thing))