简体   繁体   English

奇怪的flatMap返回类型

[英]strange flatMap return type

my problem at its simplest form: 我最简单的问题:

object test {
  import scala.language.higherKinds
  sealed trait IO[+F[+_], +A] {
    def flatMap[G[+_] >: F[_], B](f: A => IO[G, B]): IO[G, B]
  }

  trait FileOp[+A]

  val a: IO[FileOp, Int] = null
  val b: IO[FileOp, String] = null
  val c: IO[FileOp, String] = a flatMap (i => b)
}

this would give me: 这会给我:

type mismatch
found   : test.IO[[+_]test.FileOp[_],String]
required: test.IO[test.FileOp,String]
     val c: IO[FileOp, String] = a flatMap (i => b)
                                   ^

I'm expecting (in the flatMap call) both the F and G equals to FileOp and B equals to String and this is kind of right, except the [+_] before and [_] after... 我期待(在flatMap调用中) FG等于FileOpB等于String ,这是正确的,除了之后的[+_]和之后的[_] ......

can anyone explain why the return type is not what I expected and how can I fix it~? 任何人都可以解释为什么返回类型不是我的预期,我该如何解决它?

ps this is closer to what I wanted to express with the trait IO : ps这更接近我想用trait IO表达的内容:

  trait ResourceOp[+A]
  trait FileOp[+A] extends ResourceOp[A]
  trait DBOp[+A] extends ResourceOp[A]

  def readFromFile(path: String): IO[FileOp, String] = null
  def writeToDB(s: String): IO[DBOp, Int] = null
  val combinedOp: IO[ResourceOp, String] = readFromFile("/txt") flatMap writeToDB

In your type expression G[+_] >: F[_] , because of the _'s you are saying "given types A,B G[A] >: F[B] " which is not what you mean to say. 在你的类型表达式G[+_] >: F[_] ,由于_是你所说的“给定类型A,B G[A] >: F[B] ”这不是你的意思。 For a counter-example, you know that Seq[String] is not a supertype of List[Int] even though Seq >: List . 对于反例,您知道Seq[String]不是List[Int]的超类型,即使Seq >: List Instead you mean that for any given type A , G[A] >: F[A] 相反,你的意思是对于任何给定的类型AG[A] >: F[A]

Note that def foo[A >: B] is equivalent to def foo[A,B](implicit B <:< A) , 请注意, def foo[A >: B]等同于def foo[A,B](implicit B <:< A)

Here is a rearrangement of what you want which is closer to what you are trying to express: 这是你想要的重新排列,它更接近你想要表达的内容:

object test {
  import scala.language.higherKinds
  sealed trait IO[+F[+_], +A] {
    def flatMap[G[+_], B](f: A => IO[G, B])(implicit ev: <:<[F[A],G[A]]): IO[G, B]
  }

  trait ResourceOp[+A]
  trait FileOp[+A] extends ResourceOp[A]
  trait DBOp[+A] extends ResourceOp[A]

  def readFromFile(path: String): IO[FileOp, String] = null
  def writeToDB(s: String): IO[DBOp, Int] = null

  val combinedOp = readFromFile("/txt").flatMap[ResourceOp,Int](writeToDB)

}

The change I have made is to move the G >: F requirement to be the equivalent implicit parameter. 我所做的改变是将G>:F要求移动为等效的隐含参数。 Now, when you compile this you get a better error: 现在,当你编译它时,你得到一个更好的错误:

foo.scala:5: error: covariant type A occurs in contravariant position in type <:<[F[A],G[A]] of value ev
    def flatMap[G[+_], B](f: A => IO[G, B])(implicit ev: <:<[F[A],G[A]]): IO[G, B]

and when we look up the definition of <:< in Predef.scala, we can verify that on of the A's is, in fact, contravariant: 当我们在Predef.scala中查找<:<的定义时,我们可以验证A的实际上是逆变的:

sealed abstract class <:<[-From, +To] extends (From => To) with Serializable

So I don't believe you are going to get away with this unless you are willing to make ResourceOp invariant in its type parameter. 因此,除非您愿意在其类型参数中使ResourceOp不变,否则我不相信您会侥幸逃脱。 The following will compile: 以下将编译:

object test {
  import scala.language.higherKinds
  sealed trait IO[+F[_], A] {
    def flatMap[G[_], B](f: A => IO[G, B])(implicit ev: <:<[F[A],G[A]]): IO[G, B]
  }

  trait ResourceOp[A]
  trait FileOp[A] extends ResourceOp[A]
  trait DBOp[A] extends ResourceOp[A]

  def readFromFile(path: String): IO[FileOp, String] = null
  def writeToDB(s: String): IO[DBOp, Int] = null

  val combinedOp = readFromFile("/txt").flatMap[ResourceOp,Int](writeToDB)

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM