Scala: Сопоставление с образцом, когда один из двух объектов удовлетворяет некоторому условию

Я часто - написание кода, которое сравнивает два объекта и производит значение на основе того, являются ли они тем же, или отличающийся, на основе того, как они отличаются.

Таким образом, я мог бы записать:

val result = (v1,v2) match {
  case (Some(value1), Some(value2)) => "a"
  case (Some(value), None)) => "b"
  case (None, Some(value)) => "b"
  case _ = > "c"
}

Те 2-е и 3-и случаи являются тем же действительно, таким образом, я пытался писать:

val result = (v1,v2) match {
  case (Some(value1), Some(value2)) => "a"
  case (Some(value), None)) || (None, Some(value)) => "b"
  case _ = > "c"
}

Но никакая удача.

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

val result = (v1,v2) match {
  case (Some(value1), Some(value2)) => "a"
  case OneAndOnlyOne(value, v: Option[Foo] => v.isDefined ) => "b"
  case _ = > "c"
}

Таким образом, идея здесь состоит в том, что OneAndOnlyOne может быть настроен с утвержденным (isDefined в этом случае), и можно использовать его в нескольких местах.

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

Как насчет чего-то вроде этого?

val result = (v1,v2) match {
  case (Some(value1), Some(value2)) => "a"
  case new OneAndOnlyOne(v: Option[Foo] => v.isDefined )(value) => "b"
  case _ = > "c"
}

с:

class OneAndOnlyOne[T](predicate: T => Boolean) {
  def unapply( pair: Pair[T,T] ): Option[T] = {
    val (item1,item2) = pair
    val v1 = predicate(item1)
    val v2 = predicate(item2)

    if ( v1 != v2 )
      Some( if ( v1 ) item1 else item2 )
    else
      None
  }
}

Но, это не компилирует.

Кто-либо может видеть способ заставить это решение работать? Или предложите другое решение? Я, вероятно, делаю это более сложным, чем это :)

10
задан tshepang 7 March 2014 в 19:35
поделиться

5 ответов

Если вы должны поддерживать произвольные предикаты, вы можете извлечь из этого (который основан на IDEA Daniel ):

List(v1, v2) filter (_ %2 == 0) match {
    case List(value1, value2) => "a"
    case List(value) => "b"
    case _ => "c"
}

Определение функции:

def filteredMatch[T,R](values : T*)(f : T => Boolean)(p: PartialFunction[List[T], R]) : R = 
    p(List((values filter f) :_* ))

Теперь вы можете использовать это:

filteredMatch(v1,v2)(_ %2 == 0){
    case List(value1, value2) => "a"
    case List(value) => "b"
    case _ => "c"
}

Я не так уверен, если это хорошая идея (то есть читаемая). Но аккуратные упражнения тем не менее.

Было бы здорово, если бы вы могли совпадать с корпусами: Case (значение1, значение2) => ... вместо списков.

7
ответ дан 3 December 2019 в 13:54
поделиться

Я думаю, что вы задаете два несколько разных вопроса.

Один вопрос: как использовать «или» в выключателях. || не работает; |. делает. И вы не можете использовать переменные в этом случае (потому что в целом они могут сопоставить различные типы, что делает тип запутанности). Итак:

def matcher[T](a: (T,T)) = {
  a match {
    case (Some(x),Some(y)) => "both"
    case (Some(_),None) | (None,Some(_)) => "either"
    case _ => "none"
  }
}

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

Один из трюков для достижения этого является то, что для предварительного взаимодействия значений, прежде чем начать совпадать на нем, а затем использовать свои собственные сопоставленные конструи, которые вы хотите. Например,

class DiOption[+T] {
  def trinary = this
}
case class Both[T](first: T, second:T) extends DiOption[T] { }
case class OneOf[T](it: T) extends DiOption[T] { }
case class Neither() extends DiOption[Nothing] { }
implicit def sometuple2dioption[T](t2: (Option[T],Option[T])): DiOption[T] = {
  t2 match {
    case (Some(x),Some(y)) => Both(x,y)
    case (Some(x),None) => OneOf(x)
    case (None,Some(y)) => OneOf(y)
    case _ => Neither()
  }
}

// Example usage
val a = (Some("This"),None)
a trinary match {
  case Both(s,t) => "Both"
  case OneOf(s) => "Just one"
  case _ => "Nothing"
}
19
ответ дан 3 December 2019 в 13:54
поделиться

Как насчет этого:

    Welcome to Scala version 2.8.0.r20327-b20091230020149 (Java HotSpot(TM) Client VM, Java 1.6.0_17).
Type in expressions to have them evaluated.
Type :help for more information.

scala> def m(v1: Any,v2: Any) = (v1,v2) match {
     |     case (Some(x),Some(y)) => "a"
     |     case (Some(_),None) | (None,Some(_)) => "b"
     |     case _ => "c"
     | }
m: (v1: Any,v2: Any)java.lang.String

scala> m(Some(1),Some(2))
res0: java.lang.String = a

scala> m(Some(1),None)
res1: java.lang.String = b

scala> m(None,None)
res2: java.lang.String = c

scala>
6
ответ дан 3 December 2019 в 13:54
поделиться

Как насчет использования начального состояния...

int enter_dblquotes = 0;

%x DBLQUOTES
%%

\"  { BEGIN(DBLQUOTES); enter_dblquotes++; }

<DBLQUOTES>*\" 
{ 
   if (enter_dblquotes){
       handle_this_dblquotes(yytext); 
       BEGIN(INITIAL); /* revert back to normal */
       enter_dblquotes--; 
   } 
}
         ...more rules follow...

Он был аналогичен этому эффекту (flex использует % s или % x для указания ожидаемого состояния. Когда вход Flex обнаруживает кавычку, он переключается в другое состояние, а затем продолжает лексировать до тех пор, пока не достигнет другой кавычки, в которой он возвращается в нормальное состояние.

-121--1095784-

Sinkhole предприятия:

1: прочитайте, что доступ к базе данных должен быть на отдельном уровне

2: Эй, у нас есть уровень базы данных.

2 (b) Эй, у нас даже есть делегированный слой, чтобы абстрагироваться от нашей базы данных.

3: Примените закон утечек абстракций -i.e, так как в делегатах есть методы, которые получают вещи, просто предположим, что они там, чтобы использовать без мысли о последствиях - как в вызове «getPurchaseOrder ()» 10 раз подряд на странице, даже если getPurchaseOrder () является методом, который оборачивается 5 отдельных вызовов базы данных.

4: Сидите и наслаждайтесь своими веб-страницами, которые загружаются с 100 отдельными вызовами базы данных (к сожалению, не преувеличение).

Не уверен, что я бы назвал это антиобразцом? Может быть «Слои не свободны»?

-121--4294089-

Это можно сделать, если сначала определить его как значение:

val MyValThatIsCapitalized = new OneAndOnlyOne(v: Option[Foo] => v.isDefined )
val result = (v1,v2) match {
  case (Some(value1), Some(value2)) => "a"
  case MyValThatIsCapitalized(value) => "b"
  case _ = > "c"
}

Имя значения, содержащего объект-экстрактор, должно быть оприходовано.

4
ответ дан 3 December 2019 в 13:54
поделиться

на Scala 2.8:

val result = List(v1,v2).flatten match {
  case List(value1, value2) => "a"
  case List(value) => "b"
  case _ = > "c"
}

на Scala 2.7, однако, вам нужен подсказку типа, чтобы сделать его работать. Таким образом, предположение значение INT INT , например: , затем:

val result = (List(v1,v2).flatten : List[Int]) match {
  case List(value1, value2) => "a"
  case List(value) => "b"
  case _ = > "c"
}

Забавная вещь в том, что я неправильно прочитал «первым» как «Список» на Mitch Blevins Ответ, и это дало мне эту идею. : -)

3
ответ дан 3 December 2019 в 13:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: