2013-02-07 17 views
6

Korzystanie Scala 2.9.1, należy rozważyć dwa następujące przypadki Either:Dlaczego Scala ani Either.RightProjection # nie zwraca zwrotu?

scala> val er: Either[String, Int] = Right(1) 
er: Either[String,Int] = Right(1) 

scala> val el: Either[String, Int] = Left("a") 
el: Either[String,Int] = Left(a) 

To wspaniałe, że za pomocą left i right projekcje, można użyć do-listowe (poprzez tendencyjne monady prognozowanego albo) :

scala> for { r <- er.right } yield r * 2 
res6: Product with Either[String,Int] with Serializable = Right(2) 

scala> for { r <- el.right } yield r * 2 
res7: Product with Either[String,Int] with Serializable = Left(a) 

Czy ktoś może mi wyjaśnić, dlaczego decyzja nie została wykonana, aby mieć metoda filter zwraca albo? Liczyłam następujące do pracy:

scala> for { r <- er.right if r > 2 } yield r * 2 // r is NOT greater than 2! 
res8: Product with Either[String,Int] with Serializable = Left(a) 

Zamiast tego pojawia się następujący błąd: : 9: error: * wartość nie jest członkiem albo [Nothing, int] dla {r < - er. prawo jeśli r> 2} wydajność R * 2

wydaje się, że podstawowa rozmowy Either.RightProjection#filter faktycznie zwraca Option:

scala> er.right.filter(_ > 2) 
res9: Option[Either[Nothing,Int]] = None 

ten pokonuje stosowanie klauzuli if w for-Compre hension, przynajmniej sposób, w jaki próbowałem go użyć.

Czy ktoś ma wyjaśnienie, dlaczego ten projekt jest taki, jaki jest?

Odpowiedz

11

Sprowadza się to do faktu, że jeśli masz Right(b), ale predykat filtra się nie powiedzie, nie masz żadnej wartości do wstawienia Left.

Można sobie wyobrazić implementację, która działa dla twojego przypadku: Either[String, Int], przez niepowodzenie z domyślną wartością Left(""). Biblioteka standardowa Scala nie ma możliwości wygenerowania wartości dla ciebie, ponieważ nie zawiera ona koncepcji takiej jak monoid, która określałaby "pustą" wartość dla typu.

Biblioteka Scalaz nie obejmują typeclass monoid, a wersja 7 zawiera również prawo tendencyjne typ dysjunkcję, \/[A, B] (izomorficzna Either[A, B]), który ma filter metodę iff lewym typu jest monoid:

scala> \/.right[String, Int](1).filter(_ > 2) 
res1: scalaz.\/[String,Int] = -\/() 

Ale nie można tego zrobić w ogólnym przypadku - gdybyś miał Either[Nothing, Int], nigdy nie mógłbyś uzyskać lewej wartości.

+1

Co za wspaniała odpowiedź, która ma sens. Czy to oznacza, że ​​powinienem zrobić coś w stylu: dla {r <- er.right.filter (_> 2) .toRight ("a"). JoinRight.right} yield r * 2 –

+1

Możesz preferować dopasowanie do wzorca: 'er dopasuj {case Right (b) if b> 2 => Right (b * 2); case _ => Left ("a")} ' –

Powiązane problemy