我想以函数的方式编写一个通用循环,直到给定的条件为止。
我想出了以下代码:
def loop[A](a: A, f: A => A, cond: A => Boolean) : A =
if (cond(a)) a else loop(f(a), f, cond)
还有什么其他选择? scalaz中有什么东西吗?
[更新]可以使用猫并将A => A
转换为Reader
,然后使用tailRecM
。任何帮助将不胜感激。
答案 0 :(得分:2)
我同意@ wheaties的评论,但既然你要求替代方案,那么就去吧:
您可以将循环的步骤表示为迭代器,然后使用cond
导航到.find
为真的第一步:
val result = Iterator.iterate(a)(f).find(cond).get
我原本误读了,并回答好像cond
是“保持循环而真实”的情况,就像C风格的循环一样。这是我的回答,好像这就是你提出的问题。
val steps = Iterator.iterate(a)(f).takeWhile(cond)
如果你想要的只是最后一个A
值,你可以使用steps.toIterable.last
(奇怪的是,Iterator
没有定义.last
。或者,您可以使用steps.toList
将所有值收集到列表中。
示例:
val steps = Iterator.iterate(0)(_ + 1).takeWhile(_ < 10)
// remember that an iterator is read-once, so if you call .toList, you can't call .last
val result = steps.toIterable.last
// result == 9
答案 1 :(得分:1)
从您的结构来看,我认为您所描述的内容比dropWhile
更接近takeWhile
。以下是100%的教育,我不建议这是有用的或解决这个问题的正确方法。不过,您可能会发现它很有用。
如果你想成为任何容器的通用(List,Array,Option等),你需要一个方法来访问这个容器的第一个元素(a.k.a.head):
trait HasHead[I[_]]{
def head[X](of: I[X]): X
}
object HasHead {
implicit val listHasHead = new HasHead[List] {
def head[X](of: List[X]) = of.head
}
implicit val arrayHasHead = new HasHead[Array] {
def head[X](of: Array[X]) = of.head
}
//...
}
以下是适用于任何容器的通用循环:
def loop[I[_], A](
a: I[A],
f: I[A] => I[A],
cond: A => Boolean)(
implicit
hh: HasHead[I]): I[A] =
if(cond(hh.head(a))) a else loop(f(a), f, cond)
示例:
loop(List(1,2,3,4,5), (_: List[Int]).tail, (_: Int) > 2)
> List(3, 4, 5)