Last active
December 17, 2016 23:58
-
-
Save satyagraha/897e427bfb5ed203e9d3054ac6705704 to your computer and use it in GitHub Desktop.
This file contains 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
package my.cats | |
import cats.Semigroup | |
import cats.data.Validated | |
import cats.syntax.CartesianBuilder | |
import cats.syntax.cartesian._ | |
import scala.util.control.NonFatal | |
case class Message(text: String) | |
object Message extends { | |
implicit object MessageSemigroup extends Semigroup[Message] { | |
override def combine(x: Message, y: Message) = | |
Message(x.text + " | " + y.text) | |
} | |
implicit def toMessage(throwable: Throwable): Message = | |
Message(throwable.getMessage) | |
} | |
case class Name(nameRepr: String) | |
case class Date(dateRepr: String) | |
// the key issue is that this constructor may throw an exception during initial checks | |
case class User(name: Name, date: Date) { | |
require(name.nameRepr == "joe", s"only joe allowed as name") | |
} | |
object CheckCats { | |
import Validated._ | |
def tryNonFatal[E, A](f: => A)(implicit mapper: Throwable => E): Validated[E, A] = | |
try | |
valid(f) | |
catch { | |
case NonFatal(t) => invalid(mapper(t)) | |
} | |
def tryNonFatalMessage[A](f: => A): Validated[Message, A] = | |
tryNonFatal(f) | |
def validateName(nameRepr: String): Validated[Message, Name] = { | |
if (nameRepr.isEmpty) | |
invalid(Message("name cannot be blank")) | |
else | |
valid(Name(nameRepr)) | |
} | |
def validateDate(dateRepr: String): Validated[Message, Date] = { | |
if (dateRepr.isEmpty) | |
invalid(Message("date cannot be blank")) | |
else | |
tryNonFatal { | |
if (dateRepr != "now") | |
throw new IllegalArgumentException("only now allowed") | |
else | |
Date(dateRepr) | |
} | |
} | |
def main(args: Array[String]): Unit = { | |
val nameRepr = "joe" | |
val dateDepr = "now" | |
// the type of valids is: CartesianBuilder[Validated[Message, _]]#CartesianBuilder2[Name, Date] | |
val valids = validateName(nameRepr) |@| validateDate(dateDepr) | |
// the result type here is Validated[Message, Validated[Message, Date]] - want to merge these | |
val res0 = tryNonFatalMessage { | |
valids.map(User.apply) | |
} | |
println(s"res0: $res0") | |
// the result type here is Validated[Message, Date] - a bit clumsy | |
val res1 = res0.fold(m => Validated.invalid[Message, User](m), identity) | |
println(s"res1: $res1") | |
// the result type here is Validated[Message, Date] - tupling is dubious | |
val res2 = valids.tupled andThen (args => tryNonFatalMessage((User.apply _).tupled(args))) | |
println(s"res2: $res2") | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment