Пользовательские структуры управления в Scala? - PullRequest
3 голосов
/ 26 августа 2010

При программировании на Java или C ++ я несколько раз сталкивался с простым шаблоном, для которого пользовательская структура управления могла уменьшить шаблон в моем коде.Это выглядит примерно так:

 if( Predicate ){
     Action

     return Value
 }

, то есть оператор типа return if.Я пытался создать функции с сигнатурой, например foo[A,B]( pred:((A,A)=>Boolean), value:Option[B] ), но потом проверял, вернул ли я Some или None.Я запутался в операторе return.

Есть ли унаследованный способ создания таких управляющих структур на функциональных языках или, более конкретно, в Scala?

Редактировать:

Мне было не так ясно с моим описанием, и это сбивает с толку людей, которые пытаются мне помочь.Основная причина, по которой мой foo не работает, заключается в том, что он не может закорачивать оценку содержащей функции.Это

def intersect( geometry:Geometry, reference:Geometry ):Geometry = {
    return_if( withinBounds( geometry, projection ), logToString( logger, "Geometry outside " + projection.toString ), EmptyGeometry() )
    return_if( topologicallyCorrect( geometry ), intersect( correct( geometry ), reference )
    //rest of the function
}

и все еще допускает рекурсию хвоста в пределах return_if.

Ответы [ 4 ]

7 голосов
/ 26 августа 2010

Я бы использовал частичную функцию:

def whatevs[A, B](options : PartialFunction[(A,A), B]) : Option[B] = {
  val myInput = generateInput
  if(options.isDefined(myInput)) {
    Some(options(myInput))
  } else None
}

Тогда ваше использование может выглядеть следующим образом:

whateves {
   case (x,y) if x > y =>   "Biggerz"
   case (x,y) if y > x =>   "Tiny!"
}

В общем случае вам не требуется оператор возврата.Выражение if будет соответствовать последнему выражению, используемому в каждом блоке.Возможно, вам понадобится помочь компилятору выяснить тип-результат выражения if, но возвращение не требуется.

Частичные функции - это механизм для выполнения действия, если выполняется какое-либо условие.В приведенном выше примере два условия: x> y или y> x из кортежа.

Если функция whatevs не совсем то, о чем вы говорите, я бы рекомендовал использовать необработанное сопоставление с образцом.

2 голосов
/ 26 августа 2010

Хм, насколько я понимаю, вы хотите, чтобы возврат в структуре управления завершал функцию, в которую он встроен.

Так в вашем примере это должно выйти из метода intersect?

Я не уверен, возможно ли это. Поскольку возвращение внутри return_if всегда будет выходить из return_if, и я не думаю, что есть способ сообщить scala, что возвращение должно выйти из функции, в которую встроена функция return_if.

Надеюсь, я понял, что ты хотел сделать :)

2 голосов
/ 26 августа 2010

Похоже, вы используете это как условный выход из потока управления кода.

Вы можете сделать это и в Scala (просто аннотируйте метод возвращаемым типом), если это действительно самое элегантное решение проблемы. Иногда код должен действовать как многоступенчатый фильтр, и этот шаблон хорошо работает для этого.

Конечно, вы всегда можете вкладывать операторы if, но это становится неловким.

Однако есть несколько других вещей, которые следует учитывать в Scala. Можно

methodReturningOption.getOrElse(
  // All the code for the None case goes in here
)

, который обычно довольно хорошо работает при объединении различных ветвей в случае, если есть разумное значение по умолчанию (или вы в конечном итоге выбросите исключение, если его нет).

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

None match {  // Could use a real variable instead of None if it helped
  case _ if (Predicate1) => Action1; Value1
  case _ if (Predicate2) => Action2; Value2
  . . .
  case _ => ErrorHandlingPerhaps
}

Но вы также можете думать о своей проблеме по-другому, чтобы подобные предикаты стали менее полезными. (Не зная подробностей, я не могу что-то предложить.)

1 голос
/ 27 августа 2010

Я затрудняюсь понять, почему ты этого хочешь.Вот код, который вы хотите написать:

def intersect( geometry:Geometry, reference:Geometry ):Geometry = {

  return_if( withinBounds( geometry, projection ), 
    logToString( logger, "Geometry outside " + projection.toString ), 
    EmptyGeometry() )

  return_if( topologicallyCorrect( geometry ), 
    intersect( correct( geometry )), 
    reference )

    // rest of the function
}

, а вот как это выглядит в «обычной» Scala:

def intersect( geometry:Geometry, reference:Geometry ):Geometry = {

  if (withinBounds( geometry, projection )) {
    logToString( logger, "Geometry outside " + projection.toString )
    return EmptyGeometry() }

  if( topologicallyCorrect( geometry )) {
    intersect( correct( geometry ))
    return reference }

  //rest of the function
}

Для меня «обычная» версия выглядит намного яснее.С одной стороны, это очень ясно дает понять, что возвращается.Это даже не более многословно.Я подозреваю, что у вас есть более сложный вариант использования.Если вы покажете нам это, возможно, мы сможем направить вас к более подходящим схемам.

...