scala中的相互递归类型 [英] mutually recursive types in scala

查看:111
本文介绍了scala中的相互递归类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



我有一个带有bugtracker问题列表的xml文件。这是原始数据。该模型有不同的问题类型,如任务,子任务,错误,特殊bug。

现在我想解析我的原始数据到任务和子任务的层次结构:

  //字段内容的数据类型
抽象类字段
case class Id(raw:string)扩展Field
case class Status(raw:string)extends Field
...

//主模型的数据类型
抽象类问题(id:字符串,...)
案例类任务(id:Id,状态:状态...,子任务:列表[子任务])扩展问题(id,...)
case class Subtask(id:Id,status:Status ...,parent:Task)extends Issue(id,...)

我不知道这种相互递归在理论上是可能的吗?

第二个问题:

$ b p>我将模型渲染为一些wiki标记。这适用于重载的递归render():数据类型的类中的字符串。 (可能我应该有一个Renderable超类!?)

什么是最简洁的解析方式,即我想有一个递归

  fromXML:scala.xml.Elem =>问题/领域

我会把它放在哪里?它会是什么样子? IIUC,同伴是自动生成的case-classes,所以我不能添加到它?



我有这样的例子:

  def fromXml(e:Elem)= e match {
case< a> test< / a> => Id(test)
case _ =>状态(预分析)
}

但是我未能赋予函数a类型。什么该函数的类型?



我也考虑过将xml-elem直接传递给ADT的构造函数,那会是聪明?还是应该分离XML解析和模型创建?






耶稣在学习了scala基础知识并做了一些脚本之后,函数(并且思考太多的java),我终于明白了如何编写ADT,并且可以像在旧的Haskell时代一样表达自己: - ) 关于不可变,相互依赖的类的初始化,请看 对象>这个问题



B:关于您的问题 render:Foo => String 函数与可Renderable 超类,这或多或少是一种功能和面向对象方法之间的设计决定。我个人认为他们中的一个比另一个优越,这只是一个品味问题。 针对表达问题的独立可扩展解决方案可以很好地比较这两个,尽管在一个稍微更复杂的上下文中(这是一个伟大的阅读,但是)。



C:编译器,但是如果你还指定了一个伴随对象,编译器会合并这两个对象。



D:对于 Issue Field 而言,这是非常重要的常见超类型,这使得给 fromXML 。不过,你可以使用任一[问题,字段] ,但这对我来说看起来很诡异。一般来说,我会避免将返回完整节点的混合函数(例如 Task )与返回内部节点的混合函数(例如状态)。



E:您是否看过现有的解决方案,例如 scalaxb ?您可以在这里找到 这里


Is it possible to have mutual recursive types in scala?

I have a xml files with a list of bugtracker issues. It's raw data. The model has different issue-types like "tasks", "subtasks", "bug", "special-bug".

Now I want to parse my raw-data to a hierarchical structure of tasks and subtasks:

// data type for field contents
abstract class Field
case class Id(raw : string) extends Field
case class Status(raw : string) extends Field
...

// data type for primary model
abstract class Issue(id : String, ...)
case class Task(id : Id, status : Status ..., subtasks : List[Subtask] ) extends Issue(id, ...)
case class Subtask(id : Id, status : Status ..., parent: Task) extends Issue(id, ...)

I wonder if this mutual recursion is theoretically possible?

Second question:

I render the model to some wiki-markup. This works fine with an overloaded recursive render() : String in the class for the datatype. (Probably I should have a "Renderable" Superclass !?)

What would be the cleanest way for parsing, i.e. I'd like to have a recursive

fromXML : scala.xml.Elem => Issue / Field

Where would I put it? How would it look like? IIUC, the companion is autogenerated for case-classes so I cant add to it?

I have this e.g.:

def fromXml(e : Elem) = e match {
  case <a>test</a> => Id("test") 
  case _ => Status("Pre-analysed")
}

But I failed to give the function a type. What is the type of that function ?

I also thought about passing the xml-elem directly to the constructor of the ADT, would that be clever? Or should I separate XML-parsing and model-creation ?


Jesus, after learning the scala basics and doing some scripts and functions (and thinking too much java), I finally understood how to write ADTs and can express myself nearly as in good old Haskell times :-)

解决方案

A: Regarding the initialisation of immutable, mutually dependent classes, have a look at this question.

B: Regarding your question render: Foo => String function vs. Renderable superclass, this is IMHO more or less a design decision between a functional and an object-oriented approach. I personally don't think that one of them is superior to the other, it is just a matter of taste. The paper "Independently Extensible Solutions to the Expression Problem" has a nice comparison between the two, although in a slightly more elaborate context (it is a great read, however).

C: Companion objects are created by the compiler, but if you also specify a companion object, the compiler will merge the two.

D: In your current class hierarchy there is no non-trivial common supertype for Issue and Field, which makes it difficult to give a meaningful return type for fromXML. You could work with an Either[Issue, Field], though, but this looks fishy to me. In general, I would avoid mixing functions that are supposed to return full-fledged nodes (e.g., Task) with those that return "internal" nodes (e.g., Status).

E: Did you had a look at existing solutions, e.g. scalaxb? You can find more links here and here.

这篇关于scala中的相互递归类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆