Last active
January 2, 2016 03:18
-
-
Save bvenners/8242691 to your computer and use it in GitHub Desktop.
An example of giving one type multiple Applicative personalities
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Here is code that can be pasted into the REPL | |
import scalaz._ | |
import Scalaz._ | |
import org.scalautils._ | |
def all[F[_]: Applicative, A](s: String, parsers: List[String => F[A]]): F[List[A]] = parsers.traverse(p => p(s)) | |
implicit class BadDog[G, B](or: Or[G, B]) { | |
def badMap[C](bToC: B => C): G Or C = or.swap.map(bToC).swap | |
} | |
trait LowPriorityImplicit { | |
implicit def orMonad[B]: Monad[({type l[g]=g Or B})#l] = new Monad[({type l[g]=g Or B})#l] { | |
def point[G](g: => G) = Good(g) | |
def bind[G, H](fa: G Or B)(f: G => H Or B) = fa flatMap f | |
} | |
} | |
object Implicits extends LowPriorityImplicit { | |
implicit def accumulatingOrApplicative[G, B, E[b] <: Every[b]]: Applicative[({type l[g] = g Or Every[B]})#l] = | |
new Applicative[({type l[g] = g Or Every[B]})#l] { | |
override def map[G, H](fa: G Or Every[B])(f: G => H) = fa map f | |
def point[G](g: => G) = Good(g) | |
def ap[G, H](fa: => G Or Every[B])(f: => ((G => H) Or Every[B])): H Or Every[B] = | |
(fa, f) match { | |
case (Good(g), Good(f)) => Good(f(g)) | |
case (Bad(b), Good(_)) => Bad(b) | |
case (Good(f), Bad(b)) => Bad(b) | |
case (Bad(b1), Bad(b2)) => Bad(b1 ++ b2) | |
} | |
} | |
} | |
import Implicits._ | |
def toIntE(s: String): Int Or ErrorMessage = attempt(s.toInt).badMap(_.getMessage) | |
def one: String => (Int Or List[ErrorMessage]) = s => toIntE(s).badMap(List(_)) | |
def two: String => (Int Or List[ErrorMessage]) = s => toIntE(s.take(2)).badMap(List(_)) | |
def three: String => (Int Or List[ErrorMessage]) = s => toIntE(s.drop(2)).badMap(List(_)) | |
all[({ type l[a] = a Or List[ErrorMessage] })#l, Int]("1234", List(one, two, three)) | |
all[({ type l[a] = a Or List[ErrorMessage] })#l, Int]("asfasf", List(one, two, three)) | |
def oneA: String => (Int Or Every[ErrorMessage]) = s => toIntE(s).badMap(Every(_)) | |
def twoA: String => (Int Or Every[ErrorMessage]) = s => toIntE(s.take(2)).badMap(Every(_)) | |
def threeA: String => (Int Or Every[ErrorMessage]) = s => toIntE(s.drop(2)).badMap(Every(_)) | |
all[({ type l[a] = a Or Every[ErrorMessage] })#l, Int]("1234", List(oneA, twoA, threeA)) | |
all[({ type l[a] = a Or Every[ErrorMessage] })#l, Int]("asfasf", List(oneA, twoA, threeA)) | |
// And here is how it looks when you paste it into the REPL: | |
scala> import scalaz._ | |
import scalaz._ | |
scala> import Scalaz._ | |
import Scalaz._ | |
scala> import org.scalautils._ | |
import org.scalautils._ | |
scala> def all[F[_]: Applicative, A](s: String, parsers: List[String => F[A]]): F[List[A]] = parsers.traverse(p => p(s)) | |
warning: there were 1 feature warning(s); re-run with -feature for details | |
all: [F[_], A](s: String, parsers: List[String => F[A]])(implicit evidence$1: scalaz.Applicative[F])F[List[A]] | |
scala> implicit class BadDog[G, B](or: Or[G, B]) { | |
| def badMap[C](bToC: B => C): G Or C = or.swap.map(bToC).swap | |
| } | |
defined class BadDog | |
scala> trait LowPriorityImplicit { | |
| implicit def orMonad[B]: Monad[({type l[g]=g Or B})#l] = new Monad[({type l[g]=g Or B})#l] { | |
| def point[G](g: => G) = Good(g) | |
| def bind[G, H](fa: G Or B)(f: G => H Or B) = fa flatMap f | |
| } | |
| } | |
defined trait LowPriorityImplicit | |
scala> object Implicits extends LowPriorityImplicit { | |
| implicit def accumulatingOrApplicative[G, B, E[b] <: Every[b]]: Applicative[({type l[g] = g Or Every[B]})#l] = | |
| new Applicative[({type l[g] = g Or Every[B]})#l] { | |
| override def map[G, H](fa: G Or Every[B])(f: G => H) = fa map f | |
| | |
| def point[G](g: => G) = Good(g) | |
| | |
| def ap[G, H](fa: => G Or Every[B])(f: => ((G => H) Or Every[B])): H Or Every[B] = | |
| (fa, f) match { | |
| case (Good(g), Good(f)) => Good(f(g)) | |
| case (Bad(b), Good(_)) => Bad(b) | |
| case (Good(f), Bad(b)) => Bad(b) | |
| case (Bad(b1), Bad(b2)) => Bad(b1 ++ b2) | |
| } | |
| } | |
| } | |
warning: there were 1 feature warning(s); re-run with -feature for details | |
defined module Implicits | |
scala> import Implicits._ | |
import Implicits._ | |
scala> def toIntE(s: String): Int Or ErrorMessage = attempt(s.toInt).badMap(_.getMessage) | |
toIntE: (s: String)org.scalautils.Or[Int,org.scalautils.ErrorMessage] | |
scala> def one: String => (Int Or List[ErrorMessage]) = s => toIntE(s).badMap(List(_)) | |
one: String => org.scalautils.Or[Int,List[org.scalautils.ErrorMessage]] | |
scala> def two: String => (Int Or List[ErrorMessage]) = s => toIntE(s.take(2)).badMap(List(_)) | |
two: String => org.scalautils.Or[Int,List[org.scalautils.ErrorMessage]] | |
scala> def three: String => (Int Or List[ErrorMessage]) = s => toIntE(s.drop(2)).badMap(List(_)) | |
three: String => org.scalautils.Or[Int,List[org.scalautils.ErrorMessage]] | |
scala> all[({ type l[a] = a Or List[ErrorMessage] })#l, Int]("1234", List(one, two, three)) | |
res0: org.scalautils.Or[List[Int],List[String]] = Good(List(1234, 12, 34)) | |
scala> all[({ type l[a] = a Or List[ErrorMessage] })#l, Int]("asfasf", List(one, two, three)) | |
res1: org.scalautils.Or[List[Int],List[String]] = Bad(List(For input string: "asfasf")) | |
scala> def oneA: String => (Int Or Every[ErrorMessage]) = s => toIntE(s).badMap(Every(_)) | |
oneA: String => org.scalautils.Or[Int,org.scalautils.Every[org.scalautils.ErrorMessage]] | |
scala> def twoA: String => (Int Or Every[ErrorMessage]) = s => toIntE(s.take(2)).badMap(Every(_)) | |
twoA: String => org.scalautils.Or[Int,org.scalautils.Every[org.scalautils.ErrorMessage]] | |
scala> def threeA: String => (Int Or Every[ErrorMessage]) = s => toIntE(s.drop(2)).badMap(Every(_)) | |
threeA: String => org.scalautils.Or[Int,org.scalautils.Every[org.scalautils.ErrorMessage]] | |
scala> all[({ type l[a] = a Or Every[ErrorMessage] })#l, Int]("1234", List(oneA, twoA, threeA)) | |
res2: org.scalautils.Or[List[Int],org.scalautils.Every[String]] = Good(List(1234, 12, 34)) | |
scala> all[({ type l[a] = a Or Every[ErrorMessage] })#l, Int]("asfasf", List(oneA, twoA, threeA)) | |
res3: org.scalautils.Or[List[Int],org.scalautils.Every[String]] = Bad(Many(For input string: "fasf", For input string: "as", For input string: "asfasf")) |
An inferency wrapper around all
:
def allU[FA](s: String, parsers: List[String => FA])(implicit U: Unapply[Applicative, FA]): U.M[List[U.A]] =
all(s, U.leibniz.subst[({type l[a] = List[String => a]})#l](parsers))(U.TC)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Note: there was a typo in the original code I pasted in. I had an extraneous s on the end of LowPriorityImplicit, which only worked because of history in my REPL session. With s removed this now works out of the box in a project that includes only scalaz and scalautils.