首页 文章

Scala:返回类型Seq [A]或未来[Seq [A]]的泛型

提问于
浏览
3

The Problem

我有两个类如下所示:

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

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

两个类之间的唯一区别是,Now返回Seq,稍后返回Future Seq . 我希望这两个类共享相同的接口

What I Have Tried

考虑到Seq和Future [Seq]如何只需要一个类型参数,这似乎非常适合高等级的类型 .

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共享相同的界面?

3 回答

  • 1

    你需要类型组成:

    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(我本可以发誓它包括一般类型的组合,但显然不是 . )

  • 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的类型组合答案就是你正在寻找的 .

  • 4

    阿列克谢的解决方案非常聪明,可以回答你提出的问题 . 但是,我认为你提出了问题 .

    您从这两个接口开始:

    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 monad,它基本上就像它所包含的对象的惰性身份 . 同样有其他选择,但重点是你需要知道的关于 FutureNeed 的唯一事情是它们是monad . 你对待它们是一样的,你决定在其他地方使用其中一个 .

相关问题