Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>First, let's set up some type aliases because typing this out repeatedly will get old pretty fast. We'll tidy up your validation logic a little too while we're here.</p> <pre><code>type V[X] = Validation[String, X] type O[X] = Option[X] def checkInt(i: Int): V[Int] = Validation.fromEither(i != 100 either "Bad value found" or i) val v: V[O[Int]] = _ </code></pre> <p>this is where we're starting out - b1 is equivalent to your vv situation</p> <pre><code>val b1: V[O[V[Int]]] = v.map(_.map(checkInt)) </code></pre> <p>so let's sequence the option to flip over the V[O[V[Int]]] into a V[V[O[Int]]]</p> <pre><code>val b2: V[V[O[Int]]] = v.map(_.map(checkInt)).map(_.sequence[V, Int]) </code></pre> <p>or if you're feeling lambda-y it could have been</p> <pre><code>sequence[({type l[x] = Validation[String, x]})#l, Int] </code></pre> <p>next we flatten out that nested validation - we're going to pull in the Validation monad because we actually do want the fastfail behaviour here, although it's generally not the right thing to do.</p> <pre><code>implicit val monad = Validation.validationMonad[String] val b3: V[O[Int]] = v.map(_.map(checkInt)).map(_.sequence[V, Int]).join </code></pre> <p>So now we've got a Validation[String, Option[Int]], so we're there, but this is still pretty messy. Lets use some equational reasoning to tidy it up</p> <p>By the second functor law we know that:</p> <pre><code>X.map(_.f).map(_.g) = X.map(_.f.g) =&gt; val i1: V[O[Int]] = v.map(_.map(checkInt).sequence[V, Int]).join </code></pre> <p>and by the definition of a monad:</p> <pre><code>X.map(f).join = X.flatMap(f) =&gt; val i2: V[O[Int]] = v.flatMap(_.map(checkInt).sequence[V, Int]) </code></pre> <p>and then we apply the free theorem of traversal:<br> (I struggled with that bloody paper so much, but it looks like some of it sunk in!):</p> <pre><code>X.map(f).sequence = X.traverse(f andThen identity) = X.traverse(f) =&gt; val i3: V[O[Int]] = v.flatMap(_.traverse[V, Int](checkInt)) </code></pre> <p>so now we're looking at something a bit more civilised. I imagine there's some trickery to be played with the flatMap and traverse, but I've run out of inspiration.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload