2013-08-14 2 views
1

У меня есть конструкция такого рода:Scala: ленивые вычисления на коллекции (Strategy Pattern)

if(condition1) 
    lengthyOperation1 
else if(condition2) 
    lengthyOperation2 
else if(condition3) 
    lengthyOperation3 
... 
else 
    lastLengthyOperation 

Я хочу выразить примерно следующим образом:

lazy val seq = Seq(
    condition1 -> lengthyOperation1, 
    condition2 -> lengthyOperation2, 
    condition3 -> lengthyOperation3, 
    ... 
    true -> lastLengthyOperation 
) 

seq.find(_._1).match { case(_, v) => v } 

Проблема в том, что оценка последней строки выполняет все длительные операции, когда доходит до «seq». Как это сделать, чтобы длительные операции выполнялись только при необходимости?

Примечание: условия не являются возможными модели паросочетания одного и того же выражения (то есть я не могу использовать один оператор соответствия для этого)

Edit: я должен использовать поток для этого?

ответ

0

Возможно, вы имеете в виду Seq, а не Map.

Вы можете использовать Seq вместо if здесь, хотя я не считаю его читаемым.

Вы должны использовать getOrElse после find. Предположим, что каждый lengthyOperationN функция:

seq.find(_._1).map{_._2}.getOrElse(lastLengthyOperation).apply() 
+0

Спасибо! Вы правы в том, что это должен был быть Seq. – mlg

0

Проблема с подхода заключается в том, что у вас есть леность в неправильном месте. При объявлении

lazy val seq = Seq(
    condition1 -> lengthyOperation1, 
    ... 
) 

то, как только вы касаетесь seq, вся последовательность не оцениваются со всеми его длительными операциями, независимо от того, какой из них вы прикосновения. Последовательность строна в своих элементах.

Вы можете делать то, что хотите, используя Stream с, но я думаю, что это проще сделать, используя Option s, которые предназначены для этой цели. Давайте просто объявим вспомогательную неявную функцию для опций. Если он вызван на Some, он ничего не делает. Если это называется на None, он проверяет состояние и если оно выполнено, возвращается Some(result):

implicit class IfOption[A](opt: Option[A]) { 
    def ?>[B >: A](condition: Boolean, result: => B): Option[B] = 
    opt.orElse(if (condition) Some(result) else None); 
} 

Теперь мы можем сделать что-то вроде

println(
    None 
     ?> (1 != 1, "A") 
     ?> (2 == 2, "B") 
     ?> (3 == 2, "C") 
) 

где тип печатного выражения Option[String] и печатает Some(B) , или

println(
    None 
     ?> (1 != 1, "Yes") 
     ?> (2 != 2, "No") 
     ?> (3 != 2, "heck") 
     getOrElse ("ah") 
) 

, где тип является просто «String».

Смежные вопросы