将标签附加到 Scala 中的不可变案例类
我试图为一种小型语言创建一个解析器,其中包含标签和 goto 等命令:
...
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>
...
GOTO
、IFCMD
等是扩展抽象类 Core
的案例类
为了与功能/类scala/不可变对象方式保持一致,我认为像这样定义Core
是错误:
abstract class Core(var label:Option[String] = None )
但允许我用以下内容替换该部分 :
with:
| ident~":"~cmd ^^ { case l~_~c => c.label = Some(l); c }
任何人都可以指出执行此操作的“scalaish”方法吗?
(我已经尝试过 c copy (label=Some(l))
但抽象基类没有自动复制构造函数的魔力)
Im trying to create a parser for a small language with commands including labels and goto:
...
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>
...
the GOTO
, IFCMD
etc are case classes extending abstract class Core
In keeping with the functional/scala-like/immutable-objecty -way I'm thinking that defining Core
like this is wrong:
abstract class Core(var label:Option[String] = None )
but would allow me to replace the part with <APPENDLABELTO_CORE>
with:
| ident~":"~cmd ^^ { case l~_~c => c.label = Some(l); c }
Can anyone point out the "scalaish" way to do this?
( I've tried c copy (label=Some(l))
but the abstract base class hasn't got the automatic copy constructor magic )
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
完全有可能创建您自己的类似复制的方法:
如此使用:
但是,实际上,我不会太快地放弃在这里使用 vars。推断不可变值更容易,但据我所知,您得到的值在解析器中得到了很好的隔离。另一种想法是创建一个方法,在最后将所有内容转换为不可变版本,或者如果解析器代码最终将所有数据存储在其他地方,则仅使其可变。
另一种方法是使抽象类不再抽象,而是实际使其成为一个案例类。您可以从案例类派生类(但是,从案例类派生案例类是禁忌)。那么技巧就是将您可能需要保存的变量数据保存在字段中:
It is entirely possible to create your own copy-like method:
used thusly:
But, pragmatically, I wouldn't be too quick to dismiss the use of vars here. It is easier to reason about immutable values, but the ones you get are pretty well isolated within the parser, as far as I can tell. An alternative idea would be to create a method that converts everything to an immutable version at the end, or if the parser code ends up storing all the data elsewhere anyway, just leaving it mutable.
Another way to go is to make the abstract class not abstract, but to actually make it a case class. You can derive classes from a case class (deriving case classes from case classes is a no-no, however). The trick then would be to make your variable data that you may need to preserve live in a field: