2017-09-26 126 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