scala for / yield on class

时间:2016-06-12 08:09:19

标签: scala scala-breeze

我在一个关于distributions的微风文档中看到的一个例子让我摸不着头脑。

创建Rand实例后,他们会显示您可以执行以下操作:

import breeze.stats.distributions._

val pois = new Poisson(3.0);
val doublePoi: Rand[Double] = for(x <- pois) yield x.toDouble

现在,这非常酷,我可以获得一个Rand对象,当我调用Double方法时,我可以获得Int而不是samples。另一个例子可能是:

val abc = ('a' to 'z').map(_.toString).toArray
val letterDist: Rand[String] = for(x <- pois) yield {
val i = if (x > 26) x % 26 else x
abc(i)
}
val lettersSamp = letterDist.samples.take(20)
println(letterSamp)

问题是,这里发生了什么? Rand[T]不是一个集合,我到目前为止所见的所有for / yield示例都适用于集合。 scala文档并没有多提及,我发现的唯一内容就是在here中翻译for-forrehension。 这里的基本规则是什么?如何使用它(不一定是一个微风相关的答案)

2 个答案:

答案 0 :(得分:1)

Scala有将forfor-yield表达式转换为等效的flatMapmap调用的规则,也可以使用withFilter等来应用过滤器。有关如何将每个理解表达式转换为等效方法调用的实际规范可以在Scala规范的this section中找到。

如果我们采用你的例子并编译它,我们将看到for-yield表达式发生了潜在的转换。这是使用scalac -Xprint:typer命令打印出类型树:

val letterDist: breeze.stats.distributions.Rand[String] = 
        pois.map[String](((x: Int) => {
          val i: Int = if (x.>(26))
            x.%(26)
          else
            x;
          abc.apply(i)
}));

在这里,您可以看到for-yield变为map传递Int并在表达式中应用if-else。这有效,因为Rand[T] has a map method已定义:

def map[E](f: T => E): Rand[E] = MappedRand(outer, f)

答案 1 :(得分:0)

因为理解只是flatMap,map和withFilter的语法糖。用于理解的主要要求是实施这些方法。因此,它们不限于集合。用于理解的一些常见的非集合是Option,Try和Future。

在你的情况下,Poisson似乎继承了一个名为Rand的特征

https://github.com/scalanlp/breeze/blob/master/math/src/main/scala/breeze/stats/distributions/Rand.scala

此特征包含map,flatmap和withFilter。

提示:如果您使用像IntelliJ这样的IDE - 您可以按 alt + 输入进行理解,然后选择转换为desugared表达式,您将看到它是如何实现的膨胀。