2015-12-31 8 views
8

Czy można obsłużyć numer Either w podobny sposób, jak Option? W Option, mam funkcję getOrElse, w Either Chcę zwrócić Left lub przetworzyć Right. Szukam najszybszego sposobu, aby to zrobić bez żadnej tablicy podstawowej, takiej jak:Scala Mapa z prawej lub z lewej strony

val myEither:Either[String, Object] = Right(new Object()) 
myEither match { 
    case Left(leftValue) => value 
    case Right(righValue) => 
     "Success" 
} 

Odpowiedz

1

Zgaduję, że możesz zrobić w następujący sposób.

def foo(myEither: Either[String, Object]) = 
    myEither.right.map(rightValue => "Success") 
+0

Wygląda na to, że 'foo' powinien zwrócić' String', a nie 'albo '. Czy nie brakuje Ci '.getOrElse (value)' na końcu? – Marth

+0

"albo chcę zwrócić lewy, albo proces prawy" jest to, co zostało zrobione poprzez odwzorowanie właściwej projekcji. Dla 'Albo [A, B]' celem jest uzyskanie albo 'A' (pod warunkiem, że' B => A' dla 'Right') albo' B' (pod warunkiem, że 'A => B' dla' ' Left'), a następnie '.fold' jest twoim przyjacielem. – cchantep

+0

Masz rację, zbyt szybko przeczytałem to pytanie. Po prostu spojrzałem na kod i pomyślałem, że pytanie brzmi: "jak to napisać bardziej zwięźle". Mój błąd. – Marth

3

Można użyć .fold:

scala> val r: Either[Int, String] = Right("hello") 
r: Either[Int,String] = Right(hello) 

scala> r.fold(_ => "got a left", _ => "Success") 
res7: String = Success 

scala> val l: Either[Int, String] = Left(1) 
l: Either[Int,String] = Left(1) 

scala> l.fold(_ => "got a left", _ => "Success") 
res8: String = got a left 

Edit:

Ponowne czytanie pytanie jest dla mnie jasne, czy chcesz, aby zwrócić wartość w jednym Left lub innego (zdefiniowane gdzie indziej)
Jeśli jest to pierwsze, można przekazać identity do .fold, ho wever to może zmienić typ zwracany do Any:

scala> r.fold(identity, _ => "Success") 
res9: Any = Success 
4

Zarówno cchantep i Marth są dobre rozwiązania dla najbliższej problem. Ale szerzej, jest to trudne do potraktowania Albo jako coś w pełni analogicznego do Option, szczególnie jeśli pozwalasz wyrazić sekwencje potencjalnie nieudanych obliczeń dla zrozumienia. Albo ma API do projekcji (używane w rozwiązaniu cchantepa), ale jest nieco zepsuty. (Każda z projekcji włamuje się w celu zrozumienia ze strażnikami, dopasowaniem do wzorca lub przypisaniem zmiennych).

FWIW, Napisałem library, aby rozwiązać ten problem. To powiększa Albo z this API. Definiujesz "stronniczość" dla swoich Eitherów. "Prawidłowe odchylenie" oznacza, że ​​zwykły przepływ (map, get, etc) jest reprezentowany przez obiekt Right, podczas gdy obiekty Left stanowią pewien problem. (Prawe odchylenie jest konwencjonalne, chociaż możesz także zdefiniować lewe odchylenie, jeśli wolisz.) Wtedy możesz traktować Either jak Option; to wykrywa w pełni analogiczny API.

import com.mchange.leftright.BiasedEither 

import BiasedEither.RightBias._ 

val myEither:Either[String, Object] = ... 
val o = myEither.getOrElse("Substitute") 

Więcej pożytkiem można teraz traktować Albo jak prawdziwy monady Scala, czyli używać flatMap, mapa, filtr i za listowe:

val myEither : Either[String, Point] = ??? 
val nextEither = myEither.map(_.x) // Either[String,Int] 

lub

val myEither : Either[String, Point] = ??? 
def findGalaxyAtPoint(p : Point) : Either[String,Galaxy] = ??? 

val locPopPair : Either[String, (Point, Long)] = { 
    for { 
    p <- myEither  
    g <- findGalaxyAtPoint(p) 
    } yield { 
    (p, g.population) 
    } 
} 

Jeśli wszystko kroki przetwarzania powiodły się, locPopPair będzie Right[Long]. Jeśli coś pójdzie nie tak, będzie to pierwszy napotkany błąd.

To trochę bardziej skomplikowane, ale dobrym pomysłem jest zdefiniowanie pustego tokena. Spójrzmy na lekkim odmianą dla zrozumienia powyżej:

val locPopPair : Either[String, (Point, Long)] = { 
    for { 
    p <- myEither  
    g <- findGalaxyAtPoint(p) if p.x > 1000 
    } yield { 
    (p, g.population) 
    } 
} 

Co by było, gdyby test p.x > 1000 powiodło? Chcielibyśmy zwrócić pewną wartość Left, która oznacza "puste", ale nie ma uniwersalnej właściwej wartości (nie wszystkie Left są s są Left[String].Odtąd, co by się stało, kod rzuciłby NoSuchElementException. Ale możemy określić pusty znak sami, jak poniżej:

import com.mchange.leftright.BiasedEither 

val RightBias = BiasedEither.RightBias.withEmptyToken[String]("EMPTY") 
import RightBias._ 

val myEither : Either[String, Point] = ??? 
def findGalaxyAtPoint(p : Point) : Either[String,Galaxy] = ??? 

val locPopPair : Either[String, (Point, Long)] = { 
    for { 
    p <- myEither  
    g <- findGalaxyAtPoint(p) if p.x > 1000 
    } yield { 
    (p, g.population) 
    } 
} 

Teraz, jeśli test p.x > 1000 się nie powiedzie, nie będzie wyjątków, locPopPair będzie tylko Left("EMPTY").

Powiązane problemy