我在一个关于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。
这里的基本规则是什么?如何使用它(不一定是一个微风相关的答案)
答案 0 :(得分:1)
Scala有将for
和for-yield
表达式转换为等效的flatMap
和map
调用的规则,也可以使用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的特征
此特征包含map,flatmap和withFilter。
提示:如果您使用像IntelliJ这样的IDE - 您可以按 alt + 输入进行理解,然后选择转换为desugared表达式,您将看到它是如何实现的膨胀。