Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/loops/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
重复函数调用,直到我们';将在Scala中获取非空选项结果_Scala_Loops - Fatal编程技术网

重复函数调用,直到我们';将在Scala中获取非空选项结果

重复函数调用,直到我们';将在Scala中获取非空选项结果,scala,loops,Scala,Loops,Scala中的一个非常新的问题-如何在Scala中执行“重复函数直到返回的内容符合我的标准” 假设我有一个函数,我想调用它直到它返回结果,例如,定义如下: def tryToGetResult: Option[MysteriousResult] 我想出了这个解决方案,但我真的觉得它很难看: 或者,相当丑陋: var res: Option[MysteriousResult] = None while (res.isEmpty) { res = tryToGetResult } doSome

Scala中的一个非常新的问题-如何在Scala中执行“重复函数直到返回的内容符合我的标准”

假设我有一个函数,我想调用它直到它返回结果,例如,定义如下:

def tryToGetResult: Option[MysteriousResult]
我想出了这个解决方案,但我真的觉得它很难看:

或者,相当丑陋:

var res: Option[MysteriousResult] = None
while (res.isEmpty) {
  res = tryToGetResult
}
doSomethingWith(res.get)
我真的觉得有一种解决方案没有
var
,也不需要手动检查
选项是否为空

相比之下,我看到的Java替代方案在这里似乎更干净:

MysteriousResult tryToGetResult(); // returns null if no result yet

MysteriousResult res;
while ((res = tryToGetResult()) == null);
doSomethingWith(res);
雪上加霜的是,如果我们不需要
doSomethingWith(res)
并且只需要从这个函数返回它,Scala vs Java看起来是这样的:

def tryToGetResult: Option[MysteriousResult]
斯卡拉 JAVA
像这样的副作用让我有点内疚,但是这个怎么样

scala> import scala.annotation.tailrec
import scala.annotation.tailrec

scala> @tailrec
     | def lookupUntilDefined[A](f: => Option[A]): A = f match {
     |   case Some(a) => a
     |   case None => lookupUntilDefined(f)
     | }
lookupUntilDefined: [A](f: => Option[A])A
那就这样说吧

scala> def tryToGetResult(): Option[Int] = Some(10)
tryToGetResult: ()Option[Int]

scala> lookupUntilDefined(tryToGetResult())
res0: Int = 10

您可能希望为
lookupuntidefined
提供一个附加参数,以便在从未定义f的情况下它最终可以停止。

您可以使用
Stream
连续方法来精确执行以下操作:

val res = Stream.continually(tryToGetResult).flatMap(_.toStream).head
或者(可能更清楚):

这种方法相对于显式递归(除了简洁)的一个优点是,它更容易修补。比如说,我们决定,我们只想得到一千次结果。如果在此之前出现一个值,我们希望它被包装成
Some
,否则我们希望它是
None
。我们只需在上面的代码中添加几个字符:

Stream.continually(tryToGetResult).take(1000).flatMap(_.toStream).headOption

我们有我们想要的。(请注意,
是惰性的,因此即使有
take(1000)
,如果在三次调用
tryToGetResult
后出现一个值,它只会被调用三次。)

感谢您的建议!您确定尾部递归优化会接受此递归吗?从Erlang的角度来看,它需要在调用堆栈中存储每个
None
实例。如果它不
tailrec
可优化,REPL就会发出警告。在没有匹配的情况下,将有更干净的方法来实现这一点,但遗憾的是,这些方法不可优化。(忽略@PrecogIO在此发现的
tailrec
non-warning bug)从技术上讲,它会产生额外的对象,并可能产生一个巨大的
None
s列表,如果我们尝试无数次得到结果,不是吗?是的,这比我的解决方案要好得多,在
迭代器
上有一个几乎相同的
连续
,如果这是一个问题,它不会保留其结果。
val res = Stream.continually(tryToGetResult).flatMap(_.toStream).head
val res = Stream.continually(tryToGetResult).dropWhile(!_.isDefined).head
Stream.continually(tryToGetResult).take(1000).flatMap(_.toStream).headOption