1

问题

希望获得帮助以了解错误原因。原件来自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].

我不知道为什么 for 块中的 if 表达式可以,但在 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
4

1 回答 1

2

我不知道为什么 for 块中的 if 表达式可以,但在 yield 块中却不行

因为编译器对它们的翻译方式不同。前面的例子翻译成:

boolFactory.flatMap((isLeaf: Boolean) => if (isLeaf) leafFactory else innerFactor)

这产生了预期的Factory[Tree],而后者被翻译为:

boolFactory.map((isLeaf: Boolean) => if (isLeaf) leafFactory else innerFactory)

这会产生 a Factory[Factory[Tree]],而不是 a Factory[Tree],因此不符合您的方法签名。这不是关于协方差,而是关于理解如何以不同的方式翻译这些陈述。

于 2016-08-23T06:58:18.760 回答