2013-03-01 11 views
8

Poniższe nie działają.Scala Pattern Matching with Sets

object Foo { 
    def union(s: Set[Int], t: Set[Int]): Set[Int] = t match { 
     case isEmpty => s 
     case (x:xs) => union(s + x, xs) 
     case _  => throw new Error("bad input") 
    } 
} 

error: not found: type xs

Jak mogę wzór mecz na planie?

Odpowiedz

15

No x:xs oznacza x typu xs, więc to nie będzie działać. Ale, niestety, nie można wzorować zestawów dopasowań, ponieważ zestawy nie mają zdefiniowanego porządku. Lub bardziej pragmatycznie, ponieważ nie ma ekstraktora na Set.

Zawsze można definiować własne, choć:

object SetExtractor { 
    def unapplySeq[T](s: Set[T]): Option[Seq[T]] = Some(s.toSeq) 
} 

Na przykład:

scala> Set(1, 2, 3) match { 
    | case SetExtractor(x, xs @ _*) => println(s"x: $x\nxs: $xs") 
    | } 
x: 1 
xs: ArrayBuffer(2, 3) 
+3

Nice. Dla Kevina jest jasne: ponieważ nie ma zdefiniowanej kolejności na zestawach, nie należy * używać * SetExtractor z rzeczywistymi wartościami, np. 'case SetExtractor (1, xs @ _ *) => ...'; zdarza się, że działa z 'Set (1,2,3)' ale nie działa ogólnie, np. z 'Set (1,2,3,4,5)'. Daniel oferuje to jako sposób na umożliwienie dekonstrukcji wiązania, aby wybrać dowolny element z zestawu. Zauważ też, że reszta, xs, to ArrayBuffer, więc jeśli chcesz, aby był Set, użyj 'xs.toSet'. – AmigoNico

4

Po pierwsze, Twój isEmpty będzie przechwytywał każdy Set, ponieważ jest zmienną w tym kontekście. Stałe zaczynają się od dużej litery w Scali i są traktowane tylko jako stałe, jeśli ten warunek jest spełniony. Tak małe przydzieli jakikolwiek Set do isEmpty (szukałeś EmptySet?)

jak widać here, wydaje się, że dopasowywanie do wzorca nie jest bardzo korzystne dla Set s. powinieneś jawnie przekonwertować Set Do List lub Seq (toList/toSeq)

object Foo { 
    def union(s: Set[Int], t: Set[Int]): Set[Int] = t.toList match { 
     case Nil => s 
     case (x::xs) => union(s + x, xs.toSet) 
     case _  => throw new Error("bad input") 
    } 
} 
+0

Istnieje również backticked rzeczy to również pasuje do wartości. –

+0

Czy jest jakieś spowolnienie związane z konwersją 'Set' na' List'? –

+0

Tak. Możesz użyć rozwiązania pagody do celów wydajnościowych. Chciałem ci tylko pokazać, jak to zrobić z dopasowaniem wzorców. Przy okazji, w moim przykładzie przypadek '_' nigdy nie został osiągnięty – Danyel

5

Set nie jest case class i nie ma sposobu unapply.

Te dwie rzeczy sugerują, że nie można dopasować wzoru bezpośrednio na Set.
(aktualizacja: chyba zdefiniować własną ściągacza dla Set, jak Daniel poprawnie pokazuje w swojej odpowiedzi)

Powinieneś znaleźć alternatywę, polecam użyciu krotny funkcji

def union(s: Set[Int], t: Set[Int]): Set[Int] = 
    (s foldLeft t) {case (t: Set[Int], x: Int) => t + x} 

to gromadzą się elementy s na t, dodając je pojedynczo


składane

Oto docs dla krotnym pracy, jeśli to konieczne dla odniesienia:

foldLeft[B](z: B)(op: (B, A) ⇒ B): B 

Dotyczy operatora binarnego do wartości początkowej i wszystkich elementów tego zbioru, idąc od lewej do prawej.

Uwaga: może zwracać różne wyniki dla różnych serii, chyba że zamówiono podstawowy typ kolekcji. lub operator jest asocjacyjny i przemienny.

B the result type of the binary operator. 
z the start value. 
op the binary operator. 
returns the result of inserting op between consecutive elements of this set, going left to right with the start value z on the left: 

op(...op(z, x_1), x_2, ..., x_n) 
where x1, ..., xn are the elements of this set. 
+0

, więc jeśli klasa' Set' nie ma metody 'unappy()', to nie może ona zostać rozłożona przez dopasowanie? –

+1

Prawidłowo, obiekt, który ma metodę "unapply (...)" jest nazywany * extractor *, a jego celem jest zdefiniowanie sposobu wyodrębniania jego parametrów w bloku 'match/case'. To dzieje się automatycznie dla "klas przypadków". Jeśli to możliwe, powinieneś zobaczyć * ch.26 * z "Programming in Scala 2nd ed." na przykład. –

1

To co mogę wymyślić:

object Contains { 
    class Unapplier[T](val t: T) { 
    def unapply(s: Set[T]): Option[Boolean] = Some(s contains t) 
    } 
    def apply[T](t: T) = new Unapplier(t) 
} 

object SET { 
    class Unapplier[T](val set: Set[T]) { 
    def unapply(s: Set[T]): Option[Unit] = if (set == s) Some(Unit) else None 
    } 
    def apply[T](ts: T*) = new Unapplier(ts.toSet) 
} 

val Contains2 = Contains(2) 
val SET123 = SET(1, 2, 3) 

Set(1, 2, 3) match { 
    case SET123()   => println("123") 
    case Contains2(true) => println("jippy") 
    case Contains2(false) => println("ohh noo") 
} 
+0

Zobacz także: [Kodowanie w stylu: Jak używać Scala w okopach] (http://parleys.com/play/52a11b33e4b039ad2298ca78/chapter58/about) o 0:39:45 –