循环直到条件代表scala

时间:2016-12-16 20:47:40

标签: scala functional-programming

我想以函数的方式编写一个通用循环,直到给定的条件为止。

我想出了以下代码:

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。任何帮助将不胜感激。

2 个答案:

答案 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)