Created
April 29, 2015 11:56
-
-
Save blouerat/935c161a2fcb3aa9f190 to your computer and use it in GitHub Desktop.
Monad, Applicative & Json 2
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
object jsonExample { | |
import scala.language.higherKinds | |
import scalaz._, Scalaz._ | |
type Path = String | |
type JValue | |
type JObject | |
implicit class RichDisjunction[A, B](disjunction: A \/ B) { | |
def nel: NonEmptyList[A] \/ B = disjunction.leftMap(NonEmptyList(_)) | |
} | |
implicit class RichTraverse[F[_], A](fa: F[A]) { | |
def traverseV[B: Semigroup, C](f: A => Validation[B, C])(implicit tf: Traverse[F]): B \/ F[C] = tf.traverseU(fa)(f).disjunction | |
} | |
sealed trait JsonError | |
case class ParsingError(input: String) extends JsonError | |
case class MissingFieldError(path: Path) extends JsonError | |
case class ExtractionError[A](input: String) extends JsonError | |
type JsonErrors = NonEmptyList[JsonError] | |
trait JsonRead[A] { | |
def read(value: JValue): JsonErrors \/ A | |
} | |
implicit val JObjectRead = new JsonRead[JObject] { | |
def read(value: JValue): JsonErrors \/ JObject = ??? | |
} | |
implicit val ListRead = new JsonRead[List[JValue]] { | |
def read(value: JValue): JsonErrors \/ List[JValue] = ??? | |
} | |
def parse(input: String): ParsingError \/ JValue = ??? | |
def field(jObject: JObject, path: Path): MissingFieldError \/ JValue = ??? | |
def read[A](value: JValue)(implicit reader: JsonRead[A]): JsonErrors \/ A = reader.read(value) | |
def readV[A](value: JValue)(implicit reader: JsonRead[A]): Validation[JsonErrors, A] = read[A](value).validation | |
case class Result(meta: JObject, body: List[JObject]) | |
def run(input: String): JsonErrors \/ Result = | |
for { | |
json <- parse(input).nel | |
jObject <- read[JObject](json) | |
result <- { | |
val meta = field(jObject, "meta").nel.flatMap(read[JObject]) | |
val body = for { | |
jObject <- field(jObject, "body").nel | |
jValues <- read[List[JValue]](jObject) | |
jObjects <- jValues.traverseV(readV[JObject]) | |
} yield jObjects | |
val result = (meta.validation |@| body.validation)(Result) | |
result.disjunction | |
} | |
} yield result | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment