I created a Monad-like type that is a lot like the Play Json Reads[T] type, called ReadYamlValue.
trait ReadYamlValue[T] {
def read(json: YamlValue): ReadResult[T]
// ... methods include map, flatMap, etc
}
I created a cat Monad instance for this:
implicit val ReadYamlValueMonad: Monad[ReadYamlValue] = new Monad[ReadYamlValue] {
override def flatMap[A, B](fa: ReadYamlValue[A])(f: A => ReadYamlValue[B]): ReadYamlValue[B] = {
fa flatMap f
}
override def tailRecM[A, B](a: A)(f: A => ReadYamlValue[Either[A, B]]): ReadYamlValue[B] = {
ReadYamlValue.read[B] { yaml =>
#tailrec def readB(reader: ReadYamlValue[Either[A, B]]): ReadResult[B] = {
reader.read(yaml) match {
case Good(Left(nextA)) => readB(f(nextA))
case Good(Right(b)) => Good(b)
case Bad(error) => Bad(error)
}
}
readB(f(a))
}
}
override def pure[A](x: A): ReadYamlValue[A] = ReadYamlValue.success(x)
}
And then I wanted to test it with the MonadLaws and ScalaCheck.
class CatsTests extends FreeSpec with discipline.MonadTests[ReadYamlValue] {
monad[Int, Int, Int].all.check()
}
But I get:
could not find implicit value for parameter EqFA: cats.Eq[io.gloriousfuture.yaml.ReadYamlValue[Int]]
How do I define Eq for what is effectively a function? Comparing equality of a function seems like it isn't what I want... Is my ReadYamlValue class not a Monad or even a Functor for that matter?
One way to do this is to generate an arbitrary sample and compare equality of the result:
implicit def eqReadYaml[T: Eq: FormatYamlValue: Arbitrary]: Eq[ReadYamlValue[T]] = {
Eq.instance { (a, b) =>
val badYaml = arbitrary[YamlValue].getOrThrow
val goodValue = arbitrary[T].getOrThrow
val goodYaml = Yaml.write(goodValue)
Seq(badYaml, goodYaml).forall { yaml =>
(a.read(yaml), b.read(yaml)) match {
case (Good(av), Good(bv)) => Eq.eqv(av, bv)
case (Bad(ae), Bad(be)) => Eq.eqv(ae, be)
case _ => false
}
}
}
}
But this seems like it is sidestepping the definition of equality a bit. Is there a better or more canonical way to do this?
It looks like using Arbitrary instances is how Circe does it:
https://github.com/travisbrown/circe/blob/master/modules/testing/shared/src/main/scala/io/circe/testing/EqInstances.scala
They take a stream of 16 samples and compare the results.
Related
I've recently picked up the Free Monad pattern using cats in an attempt to create a DSL which can be "simplified" before execution. For example, let's say I create a language for interacting with lists:
sealed trait ListAction[A]
case class ListFilter[A](in: List[A], p: A => Boolean) extends ListAction[List[A]]
case class ListMap[A, B](in: List[A], f: A => B) extends ListAction[List[B]]
type ListProgram[A] = Free[ListAction, A]
Before executing any program built with these actions, I want to optimise it by transforming subsequent filters into a single filter and transforming subsequent maps into a single map in order to avoid iterating over the list multiple times:
// Pseudo code - doesn't compile, just illustrates my intent
def optimise[A](program: ListProgram[A]): ListProgram[A] = {
case ListFilter(ListFilter(in, p1), p2) => optimise(ListFilter(in, { a: A => p1(a) && p2(a) }))
case ListMap(ListMap(in, f1), f2) => optimise(ListMap(in, f2 compose f1))
}
Is this possible using the Free Monad, either by inspecting the last action when adding to the program or by optimising as above? Thanks very much.
Below is the code I've been using to create my programs:
trait ListProgramSyntax[A] {
def program: ListProgram[List[A]]
def listFilter(p: A => Boolean): ListProgram[List[A]] = {
program.flatMap { list: List[A] =>
Free.liftF[ListAction, List[A]](ListFilter(list, p))
}
}
def listMap[B](f: A => B): ListProgram[List[B]] = program.flatMap { list =>
Free.liftF(ListMap(list, f))
}
}
implicit def syntaxFromList[A](list: List[A]): ListProgramSyntax[A] = {
new ListProgramSyntax[A] {
override def program: ListProgram[List[A]] = Free.pure(list)
}
}
implicit def syntaxFromProgram[A](existingProgram: ListProgram[List[A]]): ListProgramSyntax[A] = {
new ListProgramSyntax[A] {
override def program: ListProgram[List[A]] = existingProgram
}
}
For example:
val program = (1 to 5).toList
.listMap(_ + 1)
.listMap(_ + 1)
.listFilter(_ % 3 == 0)
EDIT: After my colleague searched for "Free Monad optimize" using the American spelling we found a good answer to this question asserting it is not possible to do this before interpretation.
However, it must surely be possible to interpret the program to produce an optimised version of it and then interpret that to retrieve our List[A]?
I've managed to get what I want by just defining my "program" structure in a recursive ADT:
sealed trait ListAction[A]
case class ListPure[A](list: List[A]) extends ListAction[A]
case class ListFilter[A](previous: ListAction[A], p: A => Boolean) extends ListAction[A]
case class ListMap[A, B](previous: ListAction[A], f: A => B) extends ListAction[B]
trait ListActionSyntax[A] {
def previousAction: ListAction[A]
def listFilter(p: A => Boolean): ListFilter[A] = ListFilter(previousAction, p)
def listMap[B](f: A => B): ListMap[A, B] = ListMap(previousAction, f)
}
implicit def syntaxFromList[A](list: List[A]): ListActionSyntax[A] = {
new ListActionSyntax[A] {
override def previousAction: ListAction[A] = ListPure(list)
}
}
implicit def syntaxFromProgram[A](existingProgram: ListAction[A]): ListActionSyntax[A] = {
new ListActionSyntax[A] {
override def previousAction: ListAction[A] = existingProgram
}
}
def optimiseListAction[A](action: ListAction[A]): ListAction[A] = {
def trampolinedOptimise[A](action: ListAction[A]): Eval[ListAction[A]] = {
action match {
case ListFilter(ListFilter(previous, p1), p2) =>
Eval.later {
ListFilter(previous, { e: A => p1(e) && p2(e) })
}.flatMap(trampolinedOptimise(_))
case ListMap(ListMap(previous, f1), f2) =>
Eval.later {
ListMap(previous, f2 compose f1)
}.flatMap(trampolinedOptimise(_))
case ListFilter(previous, p) =>
Eval.defer(trampolinedOptimise(previous)).map { optimisedPrevious =>
ListFilter(optimisedPrevious, p)
}
case ListMap(previous, f) =>
Eval.defer(trampolinedOptimise(previous)).map { optimisedPrevious =>
ListMap(optimisedPrevious, f)
}
case pure: ListPure[A] => Eval.now(pure)
}
}
trampolinedOptimise(action).value
}
def executeListAction[A](action: ListAction[A]): List[A] = {
def trampolinedExecute[A](action: ListAction[A]): Eval[List[A]] = {
action match {
case ListPure(list) =>
Eval.now(list)
case ListMap(previous, f) =>
Eval.defer(trampolinedExecute(previous)).map { list =>
list.map(f)
}
case ListFilter(previous, p) =>
Eval.defer(trampolinedExecute(previous)).map { list =>
list.filter(p)
}
}
}
trampolinedExecute(action).value
}
This has the downside that I don't get stack-safety for free and have to ensure my optimisation and execution methods are properly trampolined.
For example, we have some services with different "containers" Future and Option:
//first service with Future
class FirstService {
getData(): XorT[Future, ServiceError, SomeData]
}
//second service with Optin
class SecondService {
getData(): XorT[Option, ServiceError, SomeData]
}
How do we can combine them to use one for comprehension to avoid type mismatch?
val result = for {
data1 <- firstService.getData()
data2 <- secondService.getData() // type mismatch required XorT[Future, ServiceError, SomeData]
} yield mergeResult(data1, data2)
XorT[F, A, B] is just a convenient wrapper over F[A Xor B], so you question essentially is: how to combine a Future and an Option. Because you still have to return a Future in some form, this mainly becomes : how to handle the Option.
There are several possibilities :
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import cats.data.XorT
import cats.implicits._
type ServiceError = String
type FutureErrorOr[A] = XorT[Future, ServiceError, A]
val fXorT: FutureErrorOr[Int] = XorT.right(Future.successful(1))
val oXorT: XorT[Option, ServiceError, Int] = XorT.right(1.some)
Turn the Option into a Future (None to Future.failed) :
val opt2fut: FutureErrorOr[Int] =
XorT(oXorT.value.fold(
Future.failed[ServiceError Xor Int](new NoSuchElementException())(
Future.successful _))
for { a <- fXort; b <- opt2fut } yield a + b
Turn the Option into a ServiceError Xor ? (None to Xor.Left) :
val opt2xor: FutureErrorOr[Int] =
XorT.fromXor[Future](oXorT.value.getOrElse("no elem".left))
for { a <- fXort; b <- opt2xor } yield a + b
Change your return type to XorT[Future, ServiceError, Option[X]] (this might not be useful if you need to use the X in the rest of the for comprehension) :
val optInside: FutureErrorOr[Option[Int]] =
XorT.fromXor[Future](oXorT.value.sequenceU)
for { a <- fXorT; b <- optInside } yield b.map(_ + a)
One of the possible ways to solve this problem make common Container monad for different types (Future, Option):
trait Container[+A] {
def map[B](f: A => B): Container[B]
def flatMap[B](f: A => Container[B]): Container[B]
}
// Empty container for value
class EmptyContainer[+A](value: A) extends Container[A] {
override def map[B](f: (A) => B): Container[B] = new EmptyContainer[B](f(value))
override def flatMap[B](f: (A) => Container[B]): Container[B] = f(value)
}
// Implement container for Option
class OptionContainer[+A](option: Option[A]) extends Container[A] {
override def map[B](f: (A) => B): Container[B] = new OptionContainer[B](option.map(f))
override def flatMap[B](f: (A) => Container[B]): Container[B] = option match {
case Some(value) => f(value)
case None => new OptionContainer[B](None)
}
}
// Implement container for Future
class FutureContainer[+A](future: Future[A]) extends Container[A] {
override def map[B](f: (A) => B): Container[B] = new FutureContainer[B](future.map(f))
// TODO: can be better!!!
override def flatMap[B](f: (A) => Container[B]): Container[B] = {
val promise = Promise[B]()
future.onComplete {
case Success(a) => f(a).map(b => promise.success(b))
case Failure(exception) => promise.failure(exception)
}
new FutureContainer[B](promise.future)
}
}
You can add an own implementation for any others types.
// Monad for Container
object Container {
implicit def monad = new Monad[Container] {
def flatMap[A, B](fa: Container[A])(f: (A) => Container[B]): Container[B] = fa.flatMap(f)
def pure[A](x: A): Container[A] = new EmptyContainer[A](x)
}
}
Our service now has view:
class SomeContainerService {
def getSomeDate(): XorT[Container, Error, SomeData] =
XorT.right(Option(SomeData()).toContainer)
def getRemoteDate(): XorT[Container, Error, SomeData] =
XorT.right(Future(SomeData()).toContainer)
}
Extensions methods for both future and option:
def toContainer = OptionContainer(option)
def toContainer = FutureContainer(future)
And for-comprehension work fine:
val result: XorT[Container, Error, SomeData] = for {
data1 <- someContainerService.getRemoteDate() // future
data2 <- someContainerService.getSomeDate() // option
} yield {
mergeResult(data1, data2)
}
I have an idea (vague), to pass (or chain) some implicit value in this manner, not introducing parameters to block f:
def block(x: Int)(f: => Unit)(implicit v: Int) = {
implicit val nv = v + x
f
}
def fun(implicit v: Int) = println(v)
such that if I used something alike:
implicit val ii: Int = 0
block(1) {
block(2) {
fun
}
}
It would print 3.
If I could say def block(x: Int)(f: implicit Int => Unit).
In other words I'm seeking for some design pattern which will allow me to implement this DSL: access some cumulative value inside nested blocks but without explicitly passing it as parameter. Is it possible? (implicits are not necessary, just a hint to emphasize that I don't want to pass that accumulator explicitly). Of course upper code will print 0.
EDIT: One of possible usages: composing http routes, in a following manner
prefix("path") {
prefix("subpath") {
post("action1") { (req, res) => do action }
get("action2") { (req, res) => do action }
}
}
Here post and get will access (how?) accumulated prefix, say List("path", "subpath") or "/path/subpath/".
Consider using DynamicVariable for this. It's really simple to use, and thread-safe:
val acc: DynamicVariable[Int] = new DynamicVariable(0)
def block(x: Int)(f: => Unit) = {
acc.withValue(acc.value + x)(f)
}
def fun = println(acc.value)
Passing state via implicit is dirty and will lead to unexpected and hard to track down bugs. What you're asking to do is build a function that can compose in such a way that nested calls accumulate over some operation and anything else uses that value to execute the function?
case class StateAccum[S](init: S){
val op: S => S
def flatMap[A <: S](f: S => StateAccum[A]) ={
val StateAccum(out) = f(s)
StateAccum(op(init, out))
}
def apply(f: S => A) = f(init)
}
which could allow you do exactly what you're after with a slight change in how you're calling it.
Now, if you really want the nested control structures, your apply would have to use an implicit value to distinguish the types of the return such that it applied the function to one and a flatMap to StateAccum returns. It gets crazy but looks like the following:
def apply[A](f: S => A)(implicit mapper: Mapper[S, A]): mapper.Out = mapper(this, f)
trait Mapper[S, A]{
type Out
def apply(s: StateAccum[S], f: S => A): Out
}
object Mapper extends LowPriorityMapper{
implicit def acuum[S, A <: S] = new Mapper[S, StateAccum[A]]{
type Out = StateAccum[A]
def apply(s: StateAccum[S], f: S => StateAccum[A]) = s.flatMap(f)
}
}
trait LowPriorityMapper{
implicit def acuum[S, A] = new Mapper[S, A]{
type Out = A
def apply(s: StateAccum[S], f: S => A) = f(s.init)
}
}
I have put all my Json converters in one file JsonUtil, and then have a convertToJson method which tries to convert any object passed to json.
Basically a structure like this:
implicit val format_A = format[A]
implicit val format_B = format[B]
def convertToJson(o: Any): JsValue =
o match {
case a: A => Json.toJson(a)
case b: B => Json.toJson(b)
case a: Any => Logger.warn("could not convert to json: "+a); JsNull
}
but with alot more formatters / cases. I don't want to import all these implicits when I need conversions (for various reasons). Is there a way to match if there exists a valid toJson conversion, so I wouldn't have to write all the cases?
like:
case o: ExistJsonConversion => Json.toJson(o)
This works.
def convertToJson[A](a: A)(implicit ev: Format[A] = null): JsValue = {
if (ev != null) {
Json.toJson(a)(ev)
} else {
println("oops")
JsNull
}
}
A bit better version below (perhaps ;)
case class Perhaps[E](value: Option[E]) {
def fold[F](ifAbsent: => F)(ifPresent: E => F): F =
value.fold(ifAbsent)(ifPresent)
}
implicit def perhaps[E](implicit ev: E = null) = Perhaps(Option(ev))
def convertToJson[A](a: A)(implicit p: Perhaps[Format[A]]): JsValue = {
p.fold[JsValue] {
println("oops")
JsNull
} { implicit ev =>
Json.toJson(a)
}
}
I'm trying to implement a container for a match (like in sports) result so that I can create matches between the winners of other matches. This concept is close to what a future monads is as it contains a to be defined value, and also close to a state monad as it hides state change. Being mostly a begginer on the topic I have implemented an initial version in scala that is surely improvable. I added a get method that I'm not sure was a good idea, and so far the only way to create a value would be Unknown(null) which is not as elegant as I'd hoped. What do you think I could do to improve this design?
case class Unknown[T](t : T) {
private var value : Option[T] = Option(t)
private var applicatives: List[T => Unit] = Nil
def set(t: T) {
if (known) {
value = Option(t)
applicatives.foreach(f => f(t))
applicatives = Nil
} else {
throw new IllegalStateException
}
}
def get : T = value.get
def apply(f: T => Unit) = value match {
case Some(x) => f(x);
case None => applicatives ::= f
}
def known = value == None
}
UPDATE: a usage example of the current implementation follows
case class Match(val home: Unknown[Team], val visit: Unknown[Team], val result: Unknown[(Int, Int)]) {
val winner: Unknown[Team] = Unknown(null)
val loser: Unknown[Team] = Unknown(null)
result.apply(result => {
if (result._1 > result._2) {
home.apply(t => winner.set(t))
visit.apply(t => loser.set(t))
} else {
home.apply(t => loser.set(t))
visit.apply(t => winner.set(t))
}
})
}
And a test snippet:
val definedUnplayedMatch = Match(Unknown(Team("A")), Unknown(Team("B")), Unknown(null));
val definedPlayedMatch = Match(Unknown(Team("D")), Unknown(Team("E")), Unknown((1,0)));
val undefinedUnplayedMatch = Match(Unknown(null), Unknown(null), Unknown(null));
definedUnplayedMatch.winner.apply(undefinedUnplayedMatch.home.set(_))
definedPlayedMatch.winner.apply(undefinedUnplayedMatch.visit.set(_))
undefinedUnplayedMatch.result.set((3,1))
definedUnplayedMatch.result.set((2,4))
undefinedUnplayedMatch.winner.get must be equalTo(Team("B"));
undefinedUnplayedMatch.loser.get must be equalTo(Team("D"));
UPDATE - CURRENT IDEA : I haven't had much time to work on this because my laptop broke down, but I though it would be useful to write the monad I have so far for those who are interested:
sealed abstract class Determine[+A] {
def map[B](f: A => B): Determine[B]
def flatMap[B](f: A => Determine[B]): Determine[B]
def filter(p: A => Boolean): Determine[A]
def foreach(b: A => Unit): Unit
}
final case class Known[+A](value: A) extends Determine[A] {
def map[B](f: A => B): Determine[B] = Known(f(value))
def flatMap[B](f: A => Determine[B]): Determine[B] = f(value)
def filter(p: A => Boolean): Determine[A] = if (p(value)) this else Unknown
def foreach(b: A => Unit): Unit = b(value)
}
final case class TBD[A](definer: () => A) extends Determine[A] {
private var value: A = _
def map[B](f: A => B): Determine[B] = {
def newDefiner(): B = {
f(cachedDefiner())
}
TBD[B](newDefiner)
}
def flatMap[B](f: A => Determine[B]): Determine[B] = {
f(cachedDefiner())
}
def filter(p: A => Boolean): Determine[A] = {
if (p(cachedDefiner()))
this
else
Unknown
}
def foreach(b: A => Unit): Unit = {
b(cachedDefiner())
}
private def cachedDefiner(): A = {
if (value == null)
value = definer()
value
}
}
case object Unknown extends Determine[Nothing] {
def map[B](f: Nothing => B): Determine[B] = this
def flatMap[B](f: Nothing => Determine[B]): Determine[B] = this
def filter(p: Nothing => Boolean): Determine[Nothing] = this
def foreach(b: Nothing => Unit): Unit = {}
}
I got rid of the set & get and now the TBD class receives instead a function that will define provide the value or null if still undefined. This idea works great for the map method, but the rest of the methods have subtle bugs.
For a simple approach, you don't need monads, with partial application is enough:
//some utilities
type Score=(Int,Int)
case class MatchResult[Team](winner:Team,loser:Team)
//assume no ties
def playMatch[Team](home:Team,away:Team)(score:Score)=
if (score._1>score._2) MatchResult(home,away)
else MatchResult(away,home)
//defined played match
val dpm= playMatch("D","E")(1,0)
//defined unplayed match, we'll apply the score later
val dum= playMatch("A","B")_
// a function that takes the dum score and applies it
// to get a defined played match from an undefined one
// still is a partial application of match because we don't have the final result yet
val uumWinner= { score:Score => playMatch (dpm.winner,dum(score).winner) _ }
val uumLoser= { score:Score => playMatch (dpm.loser,dum(score).loser) _}
//apply the scores
uumWinner (2,4)(3,1)
uumLoser (2,4)(0,1)
//scala> uumWinner (2,4)(3,1)
//res6: MatchResult[java.lang.String] = MatchResult(D,B)
//scala> uumLoser (2,4)(0,1)
//res7: MatchResult[java.lang.String] = MatchResult(A,E)
This is a starting point, I'm pretty sure it can be further refined. Maybe there we'll find the elusive monad. But I think an applicative functor will be enough.
I'll give another pass later...