2017-09-26 123 views
1

我有一个问题在斯卡拉存在与工作。创建迷你工作流引擎时,我的问题就开始了。我开始的想法,这是一个有向图,实现对后者的第一个模型,然后仿照这样的工作流程:斯卡拉存在问题

case class Workflow private(states: List[StateDef], transitions: List[_, _], override val edges: Map[String, List[StateDef]]) extends Digraph[String, StateDef, Transition[_, _]](states, edges) { ... } 

在这种情况下类,前两个字段,它们的行为状态的列表作为节点,表现为边缘的转换。

Transition参数类型的输入和输出参数,因为这应该表现为在工作流程的可执行一块,就像是某种功能:

case class Transition[-P, +R](tailState: StateDef, headState: StateDef, action: Action[P, R], condition: Option[Condition[P]] = None) extends Edge[String, StateDef](tailState, headState) { 
    def execute(param: P): Try[State[R]] = ... 
} 

我意识到很快,对付一个Workflow对象中的转换列表给我带来了类型参数的麻烦。我试图用[[Any]]和[[Nothing]]来使用参数,但我无法使其工作(gist [1])。

如果我要做Java,我会使用通配符?并使用它的'less类型安全和更动态'属性,Java必须相信我。但是Scala更加严格并且参数类型的变异和协方差很大,所以很难定义通配符并正确处理这些通配符。例如,使用forSome符号和在Workflow具有方法,我会得到这个误差(要旨[2]):

Error:(55, 24) type mismatch; 
found : List[A$A27.this.Transition[A$A27.this.CreateImage,A$A27.this.Image]] 
required: List[A$A27.this.Transition[P forSome { type P },R forSome { type R }]] 
lazy val w = Workflow(transitions) 
      ^

因此然后我创建基于性状的存在类型(要旨[3]), as explained in this article

trait Transitions { 
    type Param 
    type Return 
    val transition: Transition[Param, Return] 
    val evidenceParam: StateValue[Param] 
    val evidenceReturn: StateValue[Return] 
} 

所以,现在我可以插入这个存在于我的Workflow类是这样的:

case class Workflow private(states: List[StateDef], transitions: List[Transitions], override val edges: Map[String, List[StateDef]]) 
    extends Digraph[String, StateDef, Transitions](states, edges) 

在一个小文件的工作被证明是工作(主旨[3])。但是当我转移到真正的代码时,我的Digraph父类不喜欢这个存在的Transitions。前者需要一个Edge[ID, V]类型,其中Transition符合但当然不存在Transitions存在。

斯卡拉如何解决这种情况?使用参数类型来获得Scala中的泛型似乎很麻烦。有没有更容易的解决方案,我还没有尝试过?或者一个魔术技巧来指定Digraph之间需要Edge[ID, V]类型的正确兼容参数类型,而不是基本上擦除类型跟踪的存在类型?

对不起,因为这是令人费解的,我会尽我所能在必要时更新问题。

下面是我的一些试验和错误的要义的引用:

  1. https://gist.github.com/jimleroyer/943efd00c764880b8119786d9dd6c3a2
  2. https://gist.github.com/jimleroyer/1ce238b3934882ddc02a09485f52f407
  3. EDIT-1基于@https://gist.github.com/jimleroyer/17227b7e334d020a21deb36086b9b978

HTNW答案,我修改使用forSome的existentials的范围和更新的解决方案:https://gist.github.com/jimleroyer/2cb4ccbec13620585d21d53b4431ce22

我还是虽然正确绑定与matchTransition & getTransition方法和不使用asInstanceOf显式转换仿制药的问题。我会开一个针对这个问题的另一个问题。

回答

2

你的存在量词的范围是错误的。

R forSome { type R } 

等于Any,因为每一个类型是一种类型,所以每单类型是存在的类型的子类型,那就是Any区别特征。因此

Transition[P forSome { type P }, R forSome { type R }] 

真的

Transition[Any, Any] 

Transition s结尾几乎需要采取Any S作为参数,和你失去对回报类型的所有信息。让它

List[Transition[P, R] forSome { type P; type R }] // if every transition can have different types 
List[Transition[P, R]] forSome { type P; type R } // if all the transitions need similar types 
// The first can also be sugared to 
List[Transition[_, _]] 
// _ scopes so the forSome is placed outside the nearest enclosing grouping 

另外,我不明白,你上心Java的?是“不太安全”。使用它的代码有更高的不安全可能性,当然,因为?是有限的,但它本身是完全健全的(模null)。

+0

谢谢@HTNW,解决了一些我无法过去的编译错误。这比我想象的更简单。尽管我没有将'matchTransition'和'getTransition'工作正常,但没有强制转换为'instanceOf'。我用新版本创建了一个要点:https://gist.github.com/jimleroyer/2cb4ccbec13620585d21d53b4431ce22 你认为有一种方法可以避免这种转换吗? 尽管如此,我觉得我应该接受你的答案,至少现在都在工作。我可以为这个具体问题开一个新的问题。那会是SO标准吗? – jlr

+0

打开一个新问题,是的。 – HTNW