left
y right
sont les plus importantes. Either
est utile sans projections (vous faites surtout du filtrage), mais les projections méritent qu'on s'y attarde, car elles offrent une API beaucoup plus riche. Vous utiliserez beaucoup moins les jointures.
Either
est souvent utilisé pour signifier "une valeur correcte ou une erreur". À cet égard, il s'agit d'une extension de Option
. Lorsqu'il n'y a pas de données, au lieu de None
vous avez une erreur. Option
dispose d'une riche API. La même chose peut être mise à disposition sur Either
à condition que nous sachions, dans l'un ou l'autre cas, lequel est le résultat et lequel est l'erreur.
left
y right
La projection dit juste cela. C'est le Either
plus la connaissance supplémentaire que la valeur est respectivement à gauche ou à droite, et l'autre est l'erreur.
Par exemple, dans Option
vous pouvez cartographier, donc opt.map(f)
renvoie un Option
avec f
appliquée à la valeur de opt
s'il en a un, et toujours None
si opt
était None
. Sur une projection à gauche, il s'appliquera f
sur la valeur à gauche si c'est un Left
et le laisser inchangé s'il s'agit d'un Right
. Observez les signatures :
- En
LeftProjection[A,B]
, map[C](f: A => C): Either[C,B]
- En
RightProjection[A,B]
, map[C](f: B => C): Either[A,C]
.
left
y right
sont simplement le moyen de dire quel côté est considéré comme la valeur lorsque vous voulez utiliser l'une des routines habituelles de l'API.
Les alternatives auraient pu être :
- établir une convention, comme en Haskell, où il y avait de fortes raisons syntaxiques de mettre la valeur à droite. Quand on veut appliquer une méthode de l'autre côté (on peut très bien vouloir changer l'erreur avec un
map
par exemple), faire un swap
avant et après.
- postfixer les noms de méthodes avec Left ou Right (peut-être juste L et R). Cela empêcherait de les utiliser pour la compréhension. Avec
for
compréhensions ( flatMap
en fait, mais la notation for est assez pratique) Either
est une alternative aux exceptions (vérifiées).
Maintenant, les jointures. Gauche et Droite signifient la même chose que pour les projections, et elles sont étroitement liées à flatMap
. Considérons joinLeft
. La signature peut être déroutante :
joinLeft [A1 >: A, B1 >: B, C] (implicit ev: <:<[A1, Either[C, B1]]):
Either[C, B1]
A1
y B1
sont nécessaires d'un point de vue technique, mais ne sont pas indispensables à la compréhension.
joinLeft[C](implicit ev: <:<[A, Either[C, B])
Ce que l'implicite signifie est que la méthode ne peut être appelée que si A
est un Either[C,B]
. Cette méthode n'est pas disponible sur un Either[A,B]
en général, mais seulement sur un Either[Either[C,B], B]
. Comme pour la projection à gauche, on considère que la valeur est à gauche (ce qui serait à droite pour les joinRight
). Ce que la jointure fait, c'est aplatir cela (pensez à flatMap
). Quand on joint, on ne se soucie pas de savoir si l'erreur (B) est à l'intérieur ou à l'extérieur, on veut juste Soit [C,B]. Donc Left(Left(c)) donne Left(c), Left(Right(b)) et Right(b) donnent tous deux Right(b). La relation avec flatMap est la suivante :
joinLeft(e) = e.left.flatMap(identity)
e.left.flatMap(f) = e.left.map(f).joinLeft
Le site Option
L'équivalent fonctionnerait sur un Option[Option[A]]
, Some(Some(x))
donnerait Some(x)
les deux Some(None)
y None
donnerait None
. On peut l'écrire o.flatMap(identity). Notez que Option[A]
est isomorphe à Either[A,Unit]
(si vous utilisez des projections et des jointures à gauche) et aussi à Either[Unit, A]
(en utilisant les projections de droite).