关于理解和协方差错误的解释
Explanation on the error with for comprehension and co-variance
问题
希望获得帮助以了解错误原因。原文来自Coursera Scala Design Functional Random Generators.
任务
使用随机 int 和随机布尔值的工厂,尝试实现随机树工厂。
trait Factory[+T] {
self => // alias of 'this'
def generate: T
def map[S](f: T => S): Factory[S] = new Factory[S] {
def generate = f(self.generate)
}
def flatMap[S](f: T => Factory[S]): Factory[S] = new Factory[S] {
def generate = f(self.generate).generate
}
}
val intFactory = new Factory[Int] {
val rand = new java.util.Random
def generate = rand.nextInt()
}
val boolFactory = intFactory.map(i => i > 0)
问题
第一个块中的实现会导致错误,但如果它更改为第二个块,则不会。我相信 Factory[+T]
意味着 Factory[Inner]
和 Factory[Leaf]
都可以被视为 Factory[Tree]
.
我不知道为什么 same if 表达式在 for 块中可以,但在 yield 块中却不行。感谢解释。
trait Tree
case class Inner(left: Tree, right: Tree) extends Tree
case class Leaf(x: Int) extends Tree
def leafFactory: Factory[Leaf] = intFactory.map(i => new Leaf(i))
def innerFactory: Factory[Inner] = new Factory[Inner] {
def generate = new Inner(treeFactory.generate, treeFactory.generate)
}
def treeFactory: Factory[Tree] = for {
isLeaf <- boolFactory
} yield if (isLeaf) leafFactory else innerFactory
^^^^^^^^^^^ ^^^^^^^^^^^^
type mismatch; found : Factory[Inner] required: Tree
type mismatch; found : Factory[Leaf] required: Tree
但是,下面是可行的。
def treeFactory: Factory[Tree] = for {
isLeaf <- boolFactory
tree <- if (isLeaf) leafFactory else innerFactory
} yield tree
I have no idea why the same if expression in for block is OK but it is
not OK in yield block
因为编译器对它们的翻译不同。前面的例子翻译成:
boolFactory.flatMap((isLeaf: Boolean) => if (isLeaf) leafFactory else innerFactor)
产生预期的 Factory[Tree]
,而后者被翻译成:
boolFactory.map((isLeaf: Boolean) => if (isLeaf) leafFactory else innerFactory)
这会产生 Factory[Factory[Tree]]
,而不是 Factory[Tree]
,因此不符合您的方法签名。这与协方差无关,而是关于理解如何以不同方式翻译这些语句。
问题
希望获得帮助以了解错误原因。原文来自Coursera Scala Design Functional Random Generators.
任务
使用随机 int 和随机布尔值的工厂,尝试实现随机树工厂。
trait Factory[+T] {
self => // alias of 'this'
def generate: T
def map[S](f: T => S): Factory[S] = new Factory[S] {
def generate = f(self.generate)
}
def flatMap[S](f: T => Factory[S]): Factory[S] = new Factory[S] {
def generate = f(self.generate).generate
}
}
val intFactory = new Factory[Int] {
val rand = new java.util.Random
def generate = rand.nextInt()
}
val boolFactory = intFactory.map(i => i > 0)
问题
第一个块中的实现会导致错误,但如果它更改为第二个块,则不会。我相信 Factory[+T]
意味着 Factory[Inner]
和 Factory[Leaf]
都可以被视为 Factory[Tree]
.
我不知道为什么 same if 表达式在 for 块中可以,但在 yield 块中却不行。感谢解释。
trait Tree
case class Inner(left: Tree, right: Tree) extends Tree
case class Leaf(x: Int) extends Tree
def leafFactory: Factory[Leaf] = intFactory.map(i => new Leaf(i))
def innerFactory: Factory[Inner] = new Factory[Inner] {
def generate = new Inner(treeFactory.generate, treeFactory.generate)
}
def treeFactory: Factory[Tree] = for {
isLeaf <- boolFactory
} yield if (isLeaf) leafFactory else innerFactory
^^^^^^^^^^^ ^^^^^^^^^^^^
type mismatch; found : Factory[Inner] required: Tree
type mismatch; found : Factory[Leaf] required: Tree
但是,下面是可行的。
def treeFactory: Factory[Tree] = for {
isLeaf <- boolFactory
tree <- if (isLeaf) leafFactory else innerFactory
} yield tree
I have no idea why the same if expression in for block is OK but it is not OK in yield block
因为编译器对它们的翻译不同。前面的例子翻译成:
boolFactory.flatMap((isLeaf: Boolean) => if (isLeaf) leafFactory else innerFactor)
产生预期的 Factory[Tree]
,而后者被翻译成:
boolFactory.map((isLeaf: Boolean) => if (isLeaf) leafFactory else innerFactory)
这会产生 Factory[Factory[Tree]]
,而不是 Factory[Tree]
,因此不符合您的方法签名。这与协方差无关,而是关于理解如何以不同方式翻译这些语句。