2014-01-13 41 views
3

的問題斯卡拉:泛型對於返回類型SEQ [A]或未來[SEQ [A]]

我有像以下兩類:

class Now { 
    def do[A](f: Int => A): Seq[A] 
} 

class Later { 
    def do[A](f: Int => A): Future[Seq[A]] 
} 

之間唯一的區別這兩個類是現在返回一個Seq,然後返回一個Future Seq。我想這兩個類共享相同的接口

我曾嘗試

這似乎是一個非常適合高kinded類型,考慮如何既序列與未來[序列]應該只需要一個類型參數。

trait Do[F[_]] { 
    def do[A](f: Int => A): F[A] 
} 

// Compiles 
class Now extends Do[Seq] { 
    def do[A](f: Int => A): Seq[A] 
} 

// Does not compile. "type Seq takes type parameters" and 
// "scala.concurrent.Future[<error>] takes no type parameters, expected: one" 
class Later extends Do[Future[Seq]] { 
    def do[A](f: Int => A): Future[Seq[A]] 
} 

我是否正確使用更高版本的類型?我是否正確提供Future [Seq]?有沒有辦法允許Now和Later共享相同的界面?

回答

4

您需要類型組成:

trait Composition[F[_], G[_]] { type T[A] = F[G[A]] } 

class Later extends Do[Composition[Future, Seq]#T] { 
    def do[A](f: Int => A): Future[Seq[A]] 
} 

或者,如果你只需要在這一個地方

class Later extends Do[({ type T[A] = Future[Seq[A]] })#T] { 
    def do[A](f: Int => A): Future[Seq[A]] 
} 

scalaz(我敢發誓,它包括一般類型組成,但顯然不是。 )

+0

謝謝。引用這種類型的方法是否有名字?我從來沒有見過它,並希望閱讀更多關於它。 –

+1

@JakeGreene它被稱爲**類型lambda **。看到這個問題:http://stackoverflow.com/questions/8736164/what-are-type-lambdas-in-scala-and-what-are-their-benefits –

1

I相信你想要這個:

import scala.language.higherKinds 
import scala.concurrent.Future 

object Main { 
    type Id[A] = A 

    trait Do[F[_]] { 
    // Notice the return type now contains `Seq`. 
    def `do`[A](f: Int => A): F[Seq[A]] 
    } 

    class Now extends Do[Id] { 
    override def `do`[A](f: Int => A): Seq[A] = ??? 
    } 

    class Later extends Do[Future] { 
    override def `do`[A](f: Int => A): Future[Seq[A]] = ??? 
    } 
} 

但是,如果你想要更一般的東西,其抽象方法在其返回類型中是完全通用的,那麼@AlexeyRomanov的類型組合答案就是你正在尋找的答案。

+0

'type Id [A] = A'是一個很好的小技巧。我不知道斯卡拉是否已經有這樣的東西了 –

+1

@JakeGreene它的確如此:http://eed3si9n.com/learning-scalaz/Id.html –

1

Alexey的解決方案非常聰明,可以解答您提出的問題。但是,我認爲你提出了問題。

您開始使用這兩個接口:

class Now { 
    def do[A](f: Int => A): Seq[A] 
} 

class Later { 
    def do[A](f: Int => A): Future[Seq[A]] 
} 

要修改Later所以它實現了這一點:

trait Do[F[_]] { 
    def do[A](f: Int => A): F[A] 
} 

但是,你在這裏失去了一個機會,抽象出來的東西是否是現在或更晚。而應該更改Do是這樣的:

trait Do[F[_]] { 
    def do[A](f: Int => A): F[Seq[A]] 
} 

並改變Now這樣:

class Now { 
    def do[A](f: Int => A): Need[Seq[A]] 
} 

這裏,Need是Scalaz單子,基本上就像一個懶惰的身份它所包含的對象。還有其他的選擇,但關鍵是你需要知道的關於FutureNeed的唯一的事情就是它們是單子。你對待他們是一樣的,你決定在別處使用其中一個。