2012-10-21 35 views
1

當我碰到這個問題時,我試圖在更高類型和類型邊界上玩耍。我的用例是我想能夠使用Request的任何子類型或Request類型本身來參數化GenericAction實例。 Action trait擴展了GenericAction trait和默認類型的Request(在這種情況下,只會生成Request的匿名實例)。Scala中的更高類型/類型綁定益智遊戲

trait Request[+A] 

trait GenericAction[A, R[_] <: Request[_]] 

trait Action[A] extends GenericAction[A, Request] 

trait ActionBuilderBase[R[_] <: Request[_], G[_] <: GenericAction[_,R]] 

ActionBuilderBase具有與子特徵ActionBuilder和ActionBuilder2共享的實用方法。 ActionBuilder生成默認的Action [A]和Request [A]實例。

trait ActionBuilder extends ActionBuilderBase[Request,Action] 

到目前爲止好,但是當我試圖創建與R和GenericAction的亞型延伸ActionBuilderBase另一特徵(在這種情況下GenericAction的匿名實例將被創建),它無法編譯。我猜想原因是在第一個ActionBuilder的情況下,請求類型已經被「填充」(因爲Action [A]已經有請求類型== Request),不像下面的例子。爲了使這個例子有效,我需要「填寫」什麼?

//Fails with "GenericAction takes two type parameters, expected: one" - what should the type annotation for GenericAction look like? 
trait ActionBuilder2[R[_] <: Request[_]] extends ActionBuilderBase[R,GenericAction] 

回答

7

這將是在這種情況下很高興能夠寫這樣的事:

trait ActionBuilder2[R[_] <: Request[_]] extends 
    ActionBuilderBase[R, GenericAction[_, R]] 

爲了表明要部分應用GenericAction。不幸的是,這不是有效的Scala語法(儘管Erik Osheim有a compiler plugin,可以讓你寫一些非常相似的東西)。

您可以使用「類型拉姆達帽子戲法」,但是:

trait ActionBuilder2[R[_] <: Request[_]] extends 
    ActionBuilderBase[R, ({ type L[A] = GenericAction[A, R] })#L] 

爲它是如何工作的詳細解釋見this answer

+0

好吧,它看起來有點像我的黑魔法,但它的工作原理:-) –

+0

@BlakePettersson:是的,人們稱它爲「類型lambda _trick _」是有原因的 - 這是一種醜陋的方式來實現真正的東西應該更直接地得到語言的支持。 –