условное преобразование цикла в Scala - PullRequest
4 голосов
/ 07 октября 2009

Я бы хотел преобразовать фрагмент кода Java, который выглядит следующим образом, в Scala:

for (Iterator<Task> it = tasks.iterator(); it.hasNext() && workflow.isAutoRun();) {
    Task task = it.next();
    if (!runTask(task)) break;
}

Я не фанат понимания scala for- (не то чтобы я все равно нарушал итерацию), и я придумал следующее:

val completed = tasks.forall { task => workflow.isAutoRun && runTask(task) } 

Однако скаляр для метода forall выглядит следующим образом (курсив мой):

Примените предикат p ко всем элементам этого итерируемого объекта и верните true, если только предикат выдает true для всех элементов

Это не эквивалентно тому, что я сделал (поскольку это означает, что предикат будет оцениваться для каждого элемента независимо от того, вернулась ли предыдущая оценка false) и (на самом деле) фактически не эквивалентно тому, что 1021 * метод на самом деле, который на Iterator выглядит так:

 def forall(p: A => Boolean): Boolean = {
   var res = true
   while (res && hasNext) res = p(next)
   res
 }

В любом случае, я отвлекся: есть ли у кого-нибудь лучшие предложения о том, как должен выглядеть код scala? Я хочу увидеть что-то, что лучше передает цель:

tasks.doUntil(t => !isAutoRun || !runTask(t))

Ответы [ 5 ]

4 голосов
/ 08 октября 2009

Аналогично ответу Флавиу выше, вы можете поместить неявное определение в область видимости:

  implicit def conditionalLoop[T](s: Seq[T]) = {
    new {
      def doWhile(p: T => Boolean): Unit = {
        doWhile(s.elements)(p)
      }
      private def doWhile(it: Iterator[T])(p: T => Boolean): Unit = {
        if (it.hasNext && p(it.next)) doWhile(it)(p)
      }
    }
  }

Тогда звонить удобно:

tasks doWhile {
  t => workflow.isAutoRun && t.run
}
4 голосов
/ 07 октября 2009

В Scala 2.8 вы можете делать такие вещи:

breakable{
    tasks.foreach{ task =>
        if(!(workflow.isAutoRun&&runTask(task))) break
    }
}
2 голосов
/ 07 октября 2009

Как насчет Iterable takeWhile:

def takeWhile(p : (A) => Boolean): Iterable[A]

Возвращает самый длинный префикс этого повторяемый, элементы которого удовлетворяют предикат р

param p - тест сказуемое.

вернуться - самый длинный префикс этого итерируемого, элементы которого удовлетворяют предикату p.

2 голосов
/ 07 октября 2009

«существует» возвращает истину и завершает цикл, как только предикат возвращает истину:

val completed = tasks.exists { task =>
  if (workflow.isAutoRun) {
    runTask(task)
    false
  }
  else
    true
}

Edit:

Попробуйте это тогда:

implicit def enrichList[A](list: List[A]) = new {
  def doWhile(cond: (A) => Boolean)(body: (A) => Unit) = list exists { x =>
    if (cond(x)) {
      body(x)
      false
    }
    else
      true
  }
}

List(1, 2, 3, 4).doWhile(_ <= 3)(println) // prints "1 2 3"

tasks.doWhile(_ => workflow.isAutoRun)(runTask)
1 голос
/ 08 октября 2009

Будет ли это работать?

def doWhile[T](iter: Iterator[T])(predicate: T => Boolean): Unit = 
  if(iter.hasNext && predicate(iter.next())) 
    doWhile(iter)(predicate)

Это рекурсивный хвост, поэтому он не взрывает стек. Поскольку вы должны запустить предикат для каждого элемента итератора, предикат является функцией от T до Boolean.

Ваш код будет уменьшен до:

doWhile(it) {
   task => workflow.isAutoRun &&
           runTask(task)
   }

Из-за побочных эффектов ваших действий, действие уже выполняется, когда вы оцениваете предикат (не очень хорошо, но если так работает унаследованный код, вы должны обойти его :)

Более функциональный способ сделать это будет следующим образом:

def doWhile[T](iter: Iterator[T])(predicate: => Boolean)(action: T => Unit): Unit = 
  if(iter.hasNext && predicate) {
    action(iter.next)
    doWhile(iter)(predicate)(action) 
  }

Примечание: я мог бы найти лучшее имя для этого метода, чем doWhile, но уже поздно ...

Надеюсь, это поможет:)

- Flaviu Cipcigan

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...