Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 0abaa04

Browse files
committed
!sips/pending/_posts/2012-06-29-fixing-either.md: rewrote discussion around withFilter, now that Convert retains the type of its field
1 parent 945389c commit 0abaa04

File tree

1 file changed

+39
-19
lines changed

1 file changed

+39
-19
lines changed

sips/pending/_posts/2012-06-29-fixing-either.md

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ Note that `.e` must be appended to the value the `for` comprehension then
112112
Regarding the second example of odd behaviour, involving `if`, this
113113
was traced to the fact that the `filter` method (of `LeftProjection`
114114
and `RightProjection`) returns an `Option` instead of an `Either`,
115-
thus allowing `None` to be returned when the predicate is `false`. A
115+
thus allowing `None` to be returned when the predicate is false. A
116116
`Left` (`Right`) could not be returned in the case of a
117117
`RightProjection` (`LeftProjection`) since no value is available to go
118118
into it.
@@ -130,39 +130,59 @@ pattern-matching in `for` comprehensions involving (projections of)
130130
Therefore, a third solution has been investigated, whereby `LeftProj`
131131
(`RightProj`) has a `withFilter` method that returns a `LeftProj`
132132
(`RightProj`) containing a `Right` (`Left`) if the predicate is
133-
`false`, and where the contents of that `Right` (`Left`) is obtained
133+
false, and where the contents of that `Right` (`Left`) is obtained
134134
using an implicit conversion passed to the `withFilter` method in a
135135
second parameter list:
136136

137137
def withFilter[BB >: B](p: A => Boolean)
138-
(implicit aToB: Right.Convert => BB): LeftProj[A, BB] = {
138+
(implicit aToB: Right.Convert[A] => BB): LeftProj[A, BB] = {
139139
val e2: Either[A, BB] = e match {
140140
case Left(a) => if (p(a)) Left(a) else Right(aToB(Right.Convert(a)))
141141
case Right(b) => Right(b)
142142
}
143143
LeftProj(e2)
144144
}
145145

146-
Note that `aToB` has the type, `Right.Convert => BB`, rather than `A =>
147-
BB`, as might have been expected. This deserves the following explanation:
146+
Note that `aToB` has the type, `Right.Convert[A] => BB`, rather than
147+
`A => BB`, since we're obliged to wrap the `a` in something whose type
148+
is specific to this type of conversion--from a value in a `Left` to
149+
a value that can go into a `Right`--in order that a targeted implicit
150+
conversion may be supplied. `Convert` is a simple case class,
148151

149-
* `A => BB` only permits `for` comprehensions that do not feature definitions
150-
* `Tuple2[...] => BB` is required if there is 1 definition
151-
* `Tuple3[...] => BB` is required if there are 2 definitions, and so on
152-
* the tuple comprises one field for each definition, plus a further one (the first) for `a`
153-
* `Any` is a suitable catch-all, that must be placed in a suitable
154-
container, in order that implicit look-ups should be properly targeted
155-
* `Right.Convert` is such a container (for an `a` or tuple that is a
156-
'convert' to the right, and must therefore be converted to a `BB`
157-
by an implicit conversion)
152+
case class Convert[+A](a: A)
158153

159-
This solution therefore requires that an implicit conversion such as
160-
the following be provided whenever the method is used, as is the case
161-
when `if` or pattern-matching features in a `for` comprehension:
154+
with a `Left` counterpart for use in conversions going the other
155+
way.
162156

163-
implicit def f(convert: Right.Convert) = convert.any.toString
157+
It should be noted that `a` is sometimes a tuple:
164158

165-
Here, `any` is an `a` or tuple that is a convert to the right, and `BB` is `String`.
159+
* in `for` comprehensions involving an `if` referring to a definition,
160+
the compiler demands that an implicit conversion from a `Tuple2[A, X]`
161+
be provided, where `X` is the type of the definition, instead of a
162+
conversion from an `A`
163+
164+
* if there are two definitions, this will be a `Tuple3[A, X, Y]`, where
165+
`Y` is the type of the second definition, and so on
166+
167+
* at runtime, if the expression following `if` is false, `withFilter`
168+
is called as though the type of the `LeftProj` were
169+
`LeftProj[TupleN[A, ...], BB]` (instead of `LeftProj[A, BB]`).
170+
171+
For example, given the following `for` comprehension,
172+
173+
val either: Either[String, Int] = Right(1)
174+
val res = for {
175+
a <- either.rp
176+
b = a + 1
177+
if b > 0
178+
} yield b
179+
assert(res.e == Right(2))
180+
181+
the compiler would demand a conversion such as the following,
182+
183+
implicit def g(convert: Left.Convert[(Int, Int)]) = convert.b.toString
184+
185+
so that `res.e` would be `Left("(1,2)")` if `b > 0` were false.
166186

167187
Although this solution has been [shown][project] to work well,
168188
it has been objected to on the grounds that [`Either` strictly requires

0 commit comments

Comments
 (0)