From 9647eee6abbad46be3ef38804e3f0da9a02975ad Mon Sep 17 00:00:00 2001 From: mandubian Date: Fri, 26 Aug 2016 22:13:05 +0200 Subject: [PATCH 01/19] added onionX1/2 --- src/main/scala/Onion.scala | 54 ++++++++++++++++++++++++++++++++++++ src/main/scala/OnionT.scala | 20 +++++++++++++ src/main/scala/package.scala | 17 ++++++++++++ src/test/scala/AppSpec.scala | 21 ++++++++++++++ 4 files changed, 112 insertions(+) diff --git a/src/main/scala/Onion.scala b/src/main/scala/Onion.scala index e486368..066efad 100644 --- a/src/main/scala/Onion.scala +++ b/src/main/scala/Onion.scala @@ -372,4 +372,58 @@ trait Lifter2Low { } +} + + +trait PartialLifter1[HA, S <: Onion] { + type GA + def partialLift(ha: HA): S#Layers[GA] +} + +object PartialLifter1 { + type Aux[HA, S <: Onion, GA0] = PartialLifter1[HA, S] { type GA = GA0 } + + def apply[HA, S <: Onion](implicit lifter: PartialLifter1[HA, S]) = lifter + + + implicit def fga[F[_], GA0, O <: Onion]( + implicit lifter: Lifter[F, O] + ): PartialLifter1.Aux[F[GA0], O, GA0] = new PartialLifter1[F[GA0], O] { + type GA = GA0 + def partialLift(fga: F[GA0]): O#Layers[GA0] = lifter.lift(fga) + } + + // implicit def fga[F[_]: Functor, G[_], A0, O <: Onion]( + // implicit lifter: Lifter[F, O] + // ): PartialLifter1.Aux[F[G[A0]], O, G[A0]] = new PartialLifter1[F[G[A0]], O] { + // type GA = G[A0] + // def partialLift(fga: F[G[A0]]): O#Layers[G[A0]] = lifter.lift(fga) + // } + +} + +trait PartialLifter2[HA, S <: Onion] { + type GA + def partialLift(ha: HA): S#Layers[GA] +} + +object PartialLifter2 { + type Aux[HA, S <: Onion, GA0] = PartialLifter2[HA, S] { type GA = GA0 } + + def apply[HA, S <: Onion](implicit lifter: PartialLifter2[HA, S]) = lifter + + implicit def fga[F[_], G[_], HA0, O <: Onion]( + implicit lifter: Lifter[λ[t => F[G[t]]], O] + ): PartialLifter2.Aux[F[G[HA0]], O, HA0] = new PartialLifter2[F[G[HA0]], O] { + type GA = HA0 + def partialLift(fga: F[G[HA0]]): O#Layers[HA0] = lifter.lift(fga) + } + + // implicit def fga[F[_]: Functor, G[_], A0, O <: Onion]( + // implicit lifter: Lifter[F, O] + // ): PartialLifter1.Aux[F[G[A0]], O, G[A0]] = new PartialLifter1[F[G[A0]], O] { + // type GA = G[A0] + // def partialLift(fga: F[G[A0]]): O#Layers[G[A0]] = lifter.lift(fga) + // } + } \ No newline at end of file diff --git a/src/main/scala/OnionT.scala b/src/main/scala/OnionT.scala index 4c12e6c..fad97b3 100644 --- a/src/main/scala/OnionT.scala +++ b/src/main/scala/OnionT.scala @@ -148,6 +148,26 @@ object OnionT extends OnionTInstances { , traverser: Traverser[S] ): OnionT[TC, F, S, A] = OnionT(tcMonad.map(fa){ fa => lifter2.lift2(fa) }) + + def liftTPartial1[TC[_[_], _], F[_], S <: Onion, GA, A](fa: TC[F, GA])( + implicit + tcMonad: Monad[TC[F, ?]] + , liftp: PartialLifter1[GA, S] + , mapper: Mapper[S] + , binder: Binder[S] + // , traverser: Traverser[S] + ): OnionT[TC, F, S, liftp.GA] = + OnionT(tcMonad.map(fa){ fa => liftp.partialLift(fa) }) + + def liftTPartial2[TC[_[_], _], F[_], S <: Onion, GA, A](fa: TC[F, GA])( + implicit + tcMonad: Monad[TC[F, ?]] + , liftp: PartialLifter2[GA, S] + , mapper: Mapper[S] + , binder: Binder[S] + // , traverser: Traverser[S] + ): OnionT[TC, F, S, liftp.GA] = + OnionT(tcMonad.map(fa){ fa => liftp.partialLift(fa) }) } trait OnionTInstances { diff --git a/src/main/scala/package.scala b/src/main/scala/package.scala index 0e590c1..af727c5 100644 --- a/src/main/scala/package.scala +++ b/src/main/scala/package.scala @@ -118,6 +118,23 @@ package object freek extends LowerImplicits with HK { , traverser: Traverser[O] ): OnionT[TC, F, O, GA] = OnionT.liftP(tc) + + @inline def onionX1[O <: Onion]( + implicit + tcMonad: Monad[TC[F, ?]] + , liftp: PartialLifter1[GA, O] + , mapper: Mapper[O] + , binder: Binder[O] + ): OnionT[TC, F, O, liftp.GA] = OnionT.liftTPartial1(tc) + + @inline def onionX2[O <: Onion]( + implicit + tcMonad: Monad[TC[F, ?]] + , liftp: PartialLifter2[GA, O] + , mapper: Mapper[O] + , binder: Binder[O] + ): OnionT[TC, F, O, liftp.GA] = OnionT.liftTPartial2(tc) + } implicit class toOnionExpand[C[_]<: CopK[_], O <: Onion, A](val onion: OnionT[Free, C, O, A]) { diff --git a/src/test/scala/AppSpec.scala b/src/test/scala/AppSpec.scala index 488a568..1d6ae49 100644 --- a/src/test/scala/AppSpec.scala +++ b/src/test/scala/AppSpec.scala @@ -870,5 +870,26 @@ class AppSpec extends FlatSpec with Matchers { } + "freek" should "special cases 4" in { + sealed trait Foo1[A] + final case class Bar11(s: Int) extends Foo1[Xor[String, List[Int]]] + final case class Bar12(s: List[Int]) extends Foo1[Xor[String, Option[Int]]] + + sealed trait Foo2[A] + final case class Bar21(s: Int) extends Foo1[Xor[Long, Option[List[Int]]]] + final case class Bar22(s: List[Int]) extends Foo1[Xor[Long, Option[Int]]] + + type PRG = Foo1 :|: Foo2 :|: NilDSL + val PRG = DSL.Make[PRG] + type O = Xor[String, ?] :&: Xor[Long, ?] :&: Option :&: Bulb + + val f1: OnionT[Free, PRG.Cop, O, Unit] = for { + l1 <- Bar11(5).freek[PRG].onionX1[O] + _ <- Bar12(l1).freek[PRG].onionT[O] + l2 <- Bar21(6).freek[PRG].onionX2[O] + _ <- Bar22(l2).freek[PRG].onionT[O] + } yield (()) + + } } From 916fe9a44fc283ed36e237ad4eaa24d98584e859 Mon Sep 17 00:00:00 2001 From: mandubian Date: Tue, 30 Aug 2016 15:58:33 +0200 Subject: [PATCH 02/19] added flattener + transpile --- src/main/scala/CopK.scala | 302 ++++++++++++++++++++++++++++++++++- src/main/scala/package.scala | 26 ++- src/test/scala/AppSpec.scala | 85 ++++++++++ 3 files changed, 403 insertions(+), 10 deletions(-) diff --git a/src/main/scala/CopK.scala b/src/main/scala/CopK.scala index b1786b9..3859143 100644 --- a/src/main/scala/CopK.scala +++ b/src/main/scala/CopK.scala @@ -372,6 +372,128 @@ trait PrependHKLower { } +} + + +trait AppendHK[L[_] <: CopK[_], H[_]] { + type Out[_] <: CopK[_] + + def apply[A](ha: L[A]): Out[A] + def single[A](ha: H[A]): Out[A] + + def nat[R[_], A](out: Out[A], nat2: L ~> R, nat1: H ~> R): R[A] +} + +object AppendHK extends AppendHKLower { + + def apply[L[_] <: CopK[_], H[_]] + (implicit prep: AppendHK[L, H]): Aux[L, H, prep.Out] = prep + + type Aux[L[_] <: CopK[_], H[_], Out0[_] <: CopK[_]] = AppendHK[L, H] { type Out[t] = Out0[t] } + + implicit def in1[H1[_], H2[_]]: Aux[In1[H1, ?], H2, In2[H1, H2, ?]] = + new AppendHK[In1[H1, ?], H2] { + type Out[t] = In2[H1, H2, t] + + def apply[A](c: In1[H1, A]): Out[A] = In2l(c.head) + def single[A](ha: H2[A]): Out[A] = In2r(ha) + + def nat[R[_], A](out: In2[H1, H2, A], nat1: In1[H1, ?] ~> R, nat2: H2 ~> R): R[A] = out match { + case In2l(l) => nat1(In1(l)) + case In2r(r) => nat2(r) + } + } + + implicit def in2[H1[_], H2[_], H3[_]]: Aux[In2[H1, H2, ?], H3, In3[H1, H2, H3, ?]] = + new AppendHK[In2[H1, H2, ?], H3] { + type Out[t] = In3[H1, H2, H3, t] + + def apply[A](c: In2[H1, H2, A]): Out[A] = c match { + case In2l(left) => In3l(left) + case In2r(right) => In3m(right) + } + + def single[A](ha: H3[A]): Out[A] = In3r(ha) + + def nat[R[_], A](out: In3[H1, H2, H3, A], nat1: In2[H1, H2, ?] ~> R, nat2: H3 ~> R): R[A] = out match { + case In3l(l) => nat1(In2l(l)) + case In3m(m) => nat1(In2r(m)) + case In3r(r) => nat2(r) + } + } + + implicit def in3[H1[_], H2[_], H3[_], H4[_]]: Aux[In3[H1, H2, H3, ?], H4, AppendK[In3[H1, H2, H3, ?], In1[H4, ?], ?]] = + new AppendHK[In3[H1, H2, H3, ?], H4] { + type Out[t] = AppendK[In3[H1, H2, H3, ?], In1[H4, ?], t] + + def apply[A](c: In3[H1, H2, H3, A]): Out[A] = Aplk(c) + + def single[A](ha: H4[A]): Out[A] = Aprk(In1(ha)) + + def nat[R[_], A](out: AppendK[In3[H1, H2, H3, ?], In1[H4, ?], A], nat1: In3[H1, H2, H3, ?] ~> R, nat2: H4 ~> R): R[A] = out match { + case Aplk(m) => nat1(m) + case Aprk(In1(l)) => nat2(l) + } + } + + implicit def append1[H1[_], H2[_], L[_] <: CopK[_]]: Aux[AppendK[L, In1[H1, ?], ?], H2, AppendK[L, In2[H1, H2, ?], ?]] = + new AppendHK[AppendK[L, In1[H1, ?], ?], H2] { + type Out[t] = AppendK[L, In2[H1, H2, ?], t] + + def apply[A](c: AppendK[L, In1[H1, ?], A]): Out[A] = c match { + case Aplk(l) => Aplk(l) + case Aprk(In1(r)) => Aprk(In2l(r)) + } + + def single[A](ha: H2[A]): Out[A] = Aprk(In2r(ha)) + + def nat[RR[_], A](out: AppendK[L, In2[H1, H2, ?], A], nat1: AppendK[L, In1[H1, ?], ?] ~> RR, nat2: H2 ~> RR): RR[A] = out match { + case Aplk(r) => nat1(Aplk(r)) + case Aprk(In2l(h1)) => nat1(Aprk(In1(h1))) + case Aprk(In2r(h2)) => nat2(h2) + } + } + + implicit def append2[H1[_], H2[_], H3[_], L[_] <: CopK[_]]: Aux[AppendK[L, In2[H1, H2, ?], ?], H3, AppendK[L, In3[H1, H2, H3, ?], ?]] = + new AppendHK[AppendK[L, In2[H1, H2, ?], ?], H3] { + type Out[t] = AppendK[L, In3[H1, H2, H3, ?], t] + + def apply[A](c: AppendK[L, In2[H1, H2, ?], A]): Out[A] = c match { + case Aplk(r) => Aplk(r) + case Aprk(In2l(h1)) => Aprk(In3l(h1)) + case Aprk(In2r(h2)) => Aprk(In3m(h2)) + } + + def single[A](ha: H3[A]): Out[A] = Aprk(In3r(ha)) + + def nat[RR[_], A](out: AppendK[L, In3[H1, H2, H3, ?], A], nat1: AppendK[L, In2[H1, H2, ?], ?] ~> RR, nat2: H3 ~> RR): RR[A] = out match { + case Aplk(l) => nat1(Aplk(l)) + case Aprk(In3l(h1)) => nat1(Aprk(In2l(h1))) + case Aprk(In3m(h2)) => nat1(Aprk(In2r(h2))) + case Aprk(In3r(h3)) => nat2(h3) + } + } + +} + + +trait AppendHKLower { + + implicit def append[H[_], L[_] <: CopK[_], R[_] <: CopK[_]]: AppendHK.Aux[AppendK[L, R, ?], H, AppendK[AppendK[L, R, ?], In1[H, ?], ?]] = + new AppendHK[AppendK[L, R, ?], H] { + type Out[t] = AppendK[AppendK[L, R, ?], In1[H, ?], t] + + def apply[A](c: AppendK[L, R, A]): Out[A] = Aplk(c) + + def single[A](ha: H[A]): Out[A] = Aprk(In1(ha)) + + def nat[RR[_], A](out: AppendK[AppendK[L, R, ?], In1[H, ?], A], nat1: AppendK[L, R, ?] ~> RR, nat2: H ~> RR): RR[A] = out match { + case Aplk(l) => nat1(l) + case Aprk(In1(h)) => nat2(h) + } + } + + } trait Replace[C[_] <: CopK[_], F[_], G[_]] { @@ -466,18 +588,182 @@ trait ReplaceLower { } } -// trait Flattener[F[_] <: CopK[_]] { -// type Out[_] <: CopK[_] -// def flatten[TC[_[_], _], F[_], A](t: TC[F, A]): TC[Out, A] -// } +trait Flattener[F[_] <: CopK[_], TC[_[_], _]] { + type Out[_] <: CopK[_] + def flatten[A](t: TC[F, A]): TC[Out, A] +} -// object Flattener { +object Flattener extends FlattenerLower{ + import cats.free.Free + type Aux[F[_] <: CopK[_], TC[_[_], _], Out0[_] <: CopK[_]] = Flattener[F, TC] { type Out[t] = Out0[t] } -// type Aux[F[_] <: CopK[_], Out0[_] <: CopK[_]] = Flattener[F] { type Out[t] = Out0[t] } + implicit def in1[F[_] <: CopK[_]]: Flattener.Aux[In1[Free[F, ?], ?], Free, F] = + new Flattener[In1[Free[F, ?], ?], Free] { + type Out[t] = F[t] -// implicit def one[F[_] <: CopK[_]] -// } + def flatten[A](tca: Free[In1[Free[F, ?], ?], A]): Free[F, A] = + tca.foldMapUnsafe(new (In1[Free[F, ?], ?] ~> Free[F, ?]) { + def apply[A](in: In1[Free[F, ?], A]): Free[F, A] = in match { + case In1(free) => free + } + }) + } + + implicit def in2Left[F[_] <: CopK[_], R[_], O[_] <: CopK[_]]( + implicit ap: AppendHK.Aux[F, R, O] + ): Flattener.Aux[In2[Free[F, ?], R, ?], Free, O] = + new Flattener[In2[Free[F, ?], R, ?], Free] { + type Out[t] = O[t] + + def flatten[A](tca: Free[In2[Free[F, ?], R, ?], A]): Free[O, A] = + tca.foldMapUnsafe(new (In2[Free[F, ?], R, ?] ~> Free[O, ?]) { + def apply[A](in: In2[Free[F, ?], R, A]): Free[O, A] = in match { + case In2l(free) => free.compile(new (F ~> O) { + def apply[A](fa: F[A]): O[A] = ap(fa) + }) + + case In2r(r) => Free.liftF(ap.single(r)) + } + }) + } + + implicit def in3Left[F[_] <: CopK[_], M[_], R[_], O1[_] <: CopK[_], O2[_] <: CopK[_]]( + implicit ap1: AppendHK.Aux[F, M, O1] + , ap2: AppendHK.Aux[O1, R, O2] + ): Flattener.Aux[In3[Free[F, ?], M, R, ?], Free, O2] = + new Flattener[In3[Free[F, ?], M, R, ?], Free] { + type Out[t] = O2[t] + + def flatten[A](tca: Free[In3[Free[F, ?], M, R, ?], A]): Free[O2, A] = + tca.foldMapUnsafe(new (In3[Free[F, ?], M, R, ?] ~> Free[O2, ?]) { + def apply[A](in: In3[Free[F, ?], M, R, A]): Free[O2, A] = in match { + case In3l(free) => free.compile(new (F ~> O2) { + def apply[A](fa: F[A]): O2[A] = ap2(ap1(fa)) + }) + + case In3m(m) => Free.liftF(ap2(ap1.single(m))) + + case In3r(r) => Free.liftF(ap2.single(r)) + } + }) + } + +} + +trait FlattenerLower extends FlattenerLower2 { + import cats.free.Free + + implicit def in2Right[F[_] <: CopK[_], L[_], O[_] <: CopK[_]]( + implicit pr: PrependHK.Aux[L, F, O] + ): Flattener.Aux[In2[L, Free[F, ?], ?], Free, O] = + new Flattener[In2[L, Free[F, ?], ?], Free] { + type Out[t] = O[t] + + def flatten[A](tca: Free[In2[L, Free[F, ?], ?], A]): Free[O, A] = + tca.foldMapUnsafe(new (In2[L, Free[F, ?], ?] ~> Free[O, ?]) { + def apply[A](in: In2[L, Free[F, ?], A]): Free[O, A] = in match { + case In2l(l) => Free.liftF(pr.single(l)) + + case In2r(free) => free.compile(new (F ~> O) { + def apply[A](fa: F[A]): O[A] = pr(fa) + }) + } + }) + } + + implicit def in3Middle[F[_] <: CopK[_], L[_], R[_], O1[_] <: CopK[_], O2[_] <: CopK[_]]( + implicit pr: PrependHK.Aux[L, F, O1] + , ap: AppendHK.Aux[O1, R, O2] + ): Flattener.Aux[In3[L, Free[F, ?], R, ?], Free, O2] = + new Flattener[In3[L, Free[F, ?], R, ?], Free] { + type Out[t] = O2[t] + + def flatten[A](tca: Free[In3[L, Free[F, ?], R, ?], A]): Free[O2, A] = + tca.foldMapUnsafe(new (In3[L, Free[F, ?], R, ?] ~> Free[O2, ?]) { + def apply[A](in: In3[L, Free[F, ?], R, A]): Free[O2, A] = in match { + case In3l(l) => Free.liftF(ap(pr.single(l))) + + case In3m(free) => free.compile(new (F ~> O2) { + def apply[A](fa: F[A]): O2[A] = ap(pr(fa)) + }) + + case In3r(r) => Free.liftF(ap.single(r)) + } + }) + } + + + implicit def apkLeft[F[_] <: CopK[_], L[_] <: CopK[_], R[_] <: CopK[_], O[_] <: CopK[_]]( + implicit flt: Flattener.Aux[L, Free, O] + ): Flattener.Aux[AppendK[L, R, ?], Free, AppendK[O, R, ?]] = new Flattener[AppendK[L, R, ?], Free] { + type Out[t] = AppendK[O, R, t] + + def flatten[A](tca: Free[AppendK[L, R, ?], A]): Free[AppendK[O, R, ?], A] = + + tca.foldMapUnsafe(new (AppendK[L, R, ?] ~> Free[AppendK[O, R, ?], ?]) { + def apply[A](in: AppendK[L, R, A]): Free[AppendK[O, R, ?], A] = in match { + case Aplk(l) => + val free = Free.liftF(l) + flt.flatten(free).compile(new (O ~> AppendK[O, R, ?]) { + def apply[A](oa: O[A]): AppendK[O, R, A] = Aplk(oa) + }) + + case Aprk(r) => Free.liftF(Aprk(r)) + } + }) + } + +} + +trait FlattenerLower2 { + import cats.free.Free + + implicit def in3Right[F[_] <: CopK[_], L[_], M[_], O1[_] <: CopK[_], O2[_] <: CopK[_]]( + implicit pr1: PrependHK.Aux[M, F, O1] + , pr2: PrependHK.Aux[L, O1, O2] + ): Flattener.Aux[In3[L, M, Free[F, ?], ?], Free, O2] = + new Flattener[In3[L, M, Free[F, ?], ?], Free] { + type Out[t] = O2[t] + + def flatten[A](tca: Free[In3[L, M, Free[F, ?], ?], A]): Free[O2, A] = + tca.foldMapUnsafe(new (In3[L, M, Free[F, ?], ?] ~> Free[O2, ?]) { + def apply[A](in: In3[L, M, Free[F, ?], A]): Free[O2, A] = in match { + case In3l(l) => Free.liftF(pr2.single(l)) + + case In3m(m) => Free.liftF(pr2(pr1.single(m))) + + case In3r(free) => free.compile(new (F ~> O2) { + def apply[A](fa: F[A]): O2[A] = pr2(pr1(fa)) + }) + + } + }) + } + + + implicit def ApkRight[F[_] <: CopK[_], L[_] <: CopK[_], R[_] <: CopK[_], O[_] <: CopK[_]]( + implicit flt: Flattener.Aux[R, Free, O] + ): Flattener.Aux[AppendK[L, R, ?], Free, AppendK[L, O, ?]] = new Flattener[AppendK[L, R, ?], Free] { + type Out[t] = AppendK[L, O, t] + + def flatten[A](tca: Free[AppendK[L, R, ?], A]): Free[AppendK[L, O, ?], A] = + + tca.foldMapUnsafe(new (AppendK[L, R, ?] ~> Free[AppendK[L, O, ?], ?]) { + def apply[A](in: AppendK[L, R, A]): Free[AppendK[L, O, ?], A] = in match { + case Aplk(l) => + Free.liftF(Aplk(l)) + + case Aprk(r) => + val free = Free.liftF(r) + flt.flatten(free).compile(new (O ~> AppendK[L, O, ?]) { + def apply[A](oa: O[A]): AppendK[L, O, A] = Aprk(oa) + }) + + } + }) + } +} // object CopAppend extends CopAppendLower { diff --git a/src/main/scala/package.scala b/src/main/scala/package.scala index af727c5..42921bf 100644 --- a/src/main/scala/package.scala +++ b/src/main/scala/package.scala @@ -53,6 +53,24 @@ package object freek extends LowerImplicits with HK { ): G[A] = free.foldMapUnsafe(new (F ~> G) { def apply[A](fa: F[A]): G[A] = i.nat(sub(fa)) }) + + def flatten[O[_] <: CopK[_]](implicit flt: Flattener.Aux[F, Free, O]): Free[O, A] = flt.flatten(free) + + def transpile[F2[_] <: CopK[_], G[_] <: CopK[_], O[_] <: CopK[_]](i: Interpreter[F2, G])( + implicit + sub:SubCop[F, F2] + , flt: Flattener.Aux[G, Free, O] + ): Free[O, A] = flt.flatten(free.compile(new (F ~> G) { + def apply[A](fa: F[A]): G[A] = i.nat(sub(fa)) + })) + + def transpile[F2[_] <: CopK[_], G[_] <: CopK[_], O[_] <: CopK[_]](i: F2 ~> G)( + implicit + sub:SubCop[F, F2] + , flt: Flattener.Aux[G, Free, O] + ): Free[O, A] = flt.flatten(free.compile(new (F ~> G) { + def apply[A](fa: F[A]): G[A] = i(sub(fa)) + })) } implicit class FreeExtend[F[_], A](val free: Free[F, A]) extends AnyVal { @@ -200,7 +218,7 @@ package object freek extends LowerImplicits with HK { } package freek { - trait LowerImplicits { + trait LowerImplicits extends LowerImplicits2 { implicit class toOnionT0[TC[_[_], _], F[_], A](val tc: TC[F, A]) { @inline def onionT[O <: Onion]( @@ -215,7 +233,11 @@ package freek { } - implicit def toInterpreter[F[_], R[_]](nat: F ~> R): Interpreter[In1[F, ?], R] = Interpreter(nat) + implicit def toInterpreterCopK[F[_] <: CopK[_], R[_]](nat: F ~> R): Interpreter[F, R] = new Interpreter(nat) } + + trait LowerImplicits2 { + implicit def toInterpreter[F[_], R[_]](nat: F ~> R): Interpreter[In1[F, ?], R] = Interpreter(nat) + } } \ No newline at end of file diff --git a/src/test/scala/AppSpec.scala b/src/test/scala/AppSpec.scala index 1d6ae49..0520dec 100644 --- a/src/test/scala/AppSpec.scala +++ b/src/test/scala/AppSpec.scala @@ -891,5 +891,90 @@ class AppSpec extends FlatSpec with Matchers { } yield (()) } + + "freek" should "transpile" in { + object Program { + sealed trait Foo1[A] + final case class Bar11(s: Int) extends Foo1[Int] + + sealed trait Foo2[A] + final case class Bar21(s: String) extends Foo2[String] + + type PRG = Foo1 :|: Foo2 :|: NilDSL + val PRG = DSL.Make[PRG] + + val program = for { + _ <- Bar11(5).freek[PRG] + _ <- Bar21("1.234").freek[PRG] + } yield (()) + } + + object OtherProgram { + + sealed trait Foo3[A] + final case class Bar31(s: String) extends Foo3[Float] + + sealed trait Foo4[A] + final case class Bar41(s: Float) extends Foo4[String] + + type PRG = Foo3 :|: Foo4 :|: NilDSL + val PRG = DSL.Make[PRG] + + // this is our transpiler transforming a Foo2 into another free program + val transpiler = new (Program.Foo2 ~> Free[PRG.Cop, ?]) { + + def apply[A](f: Program.Foo2[A]): Free[PRG.Cop, A] = f match { + case Program.Bar21(s) => + for { + f <- Bar31(s).freek[PRG] + s <- Bar41(f).freek[PRG] + } yield (s) + } + } + } + + import Program._ + import OtherProgram._ + + // 1/ CopKNat[Program.PRG.Cop] creates a Program.PRG.Cop ~> Program.PRG.Cop + // 2/ .replace creates a natural trans that replaces Program.Foo2 in Program.PRG.Cop by Free[OtherProgram.PRG.Cop, ?] using transpiler + // 3/ The result is a terrible natural transformation (don't try to write that type, it's too ugly, let's scalac do it) : + // (Foo1 :|: Foo2 :|: NilDSL) ~> (Foo1 :|: Free[OtherProgram.PRG.Cop, ?] :|: NilDSL) + val transpileNat = CopKNat[Program.PRG.Cop].replace(OtherProgram.transpiler) + + // Transpile does 2 operations: + // 1/ Replaces Foo2 in Program.PRG.Cop by Free[OtherProgram.PRG.Cop, A] + // -> OtherProgram.transpiler natural transformation converts Foo2 into the free program Free[OtherProgram.PRG.Cop, A] + // -> New PRG.Cop is then Foo1 :|: Free[OtherProgram.PRG.Cop, ?] :|: NilDSL + // + // 2/ Flattens Free[(Foo1 :|: Free[(Foo3 :|: Foo4 :|: NilDSL)#Cop, ?] :|: NilDSL)#Cop, A] into + // Free[(Foo1 :|: Foo3 :|: Foo4 :|: NilDSL)#Cop, A] + val free = Program.program.transpile(transpileNat) + // Same as + // val free2 = Program.f.compile(transpileNat).flatten + + // Write our interpreters for new program (Foo1, Foo3, Foo4) + val foo1Future = new (Foo1 ~> Future) { + def apply[A](a: Foo1[A]) = a match { + case Bar11(i) => Future { i } + } + } + + val foo3Future = new (Foo3 ~> Future) { + def apply[A](a: Foo3[A]) = a match { + case Bar31(s) => Future { s.toFloat } + } + } + + val foo4Future = new (Foo4 ~> Future) { + def apply[A](a: Foo4[A]) = a match { + case Bar41(s) => Future { s.toString } + } + } + + val r = Await.result(free.interpret(foo1Future :&: foo3Future :&: foo4Future), 2.seconds) + println("r:"+r) + } + } From d37307fe36ed225c68f463ac49311c646612872f Mon Sep 17 00:00:00 2001 From: mandubian Date: Wed, 31 Aug 2016 22:51:18 +0200 Subject: [PATCH 03/19] bumped version to 0.6.1 --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index c6f7e85..1ee6b05 100644 --- a/build.sbt +++ b/build.sbt @@ -1,6 +1,6 @@ lazy val commonSettings = Seq( organization := "com.projectseptember" - , version := "0.6.0" + , version := "0.6.1" , resolvers ++= Seq( Resolver.mavenLocal , Resolver.sonatypeRepo("releases") From e26c398c09397847cfdb7b50ff2c240b84b8beec Mon Sep 17 00:00:00 2001 From: mandubian Date: Fri, 21 Oct 2016 23:30:06 +0200 Subject: [PATCH 04/19] added dsl extension --- build.sbt | 2 ++ src/test/scala/AppSpec.scala | 69 ++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/build.sbt b/build.sbt index 1ee6b05..97cc572 100644 --- a/build.sbt +++ b/build.sbt @@ -11,12 +11,14 @@ lazy val commonSettings = Seq( , licenses += ("Apache-2.0", url("http://www.apache.org/licenses/LICENSE-2.0")) , addCompilerPlugin("com.milessabin" % "si2712fix-plugin" % "1.2.0" cross CrossVersion.full) , addCompilerPlugin("org.spire-math" %% "kind-projector" % "0.7.1") + // , addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.full) , libraryDependencies ++= Seq( "org.typelevel" %% "cats" % "0.7.0" , "com.milessabin" % "si2712fix-library" % "1.2.0" cross CrossVersion.full , "org.scalatest" % "scalatest_2.11" % "3.0.0" % "test" , "org.typelevel" %% "discipline" % "0.4" % "test" , "org.typelevel" %% "cats-laws" % "0.6.1" + // , "org.scala-lang" % "scala-reflect" % scalaVersion.value % "provided" ) ) diff --git a/src/test/scala/AppSpec.scala b/src/test/scala/AppSpec.scala index 0520dec..055e2b0 100644 --- a/src/test/scala/AppSpec.scala +++ b/src/test/scala/AppSpec.scala @@ -892,6 +892,75 @@ class AppSpec extends FlatSpec with Matchers { } + "freek" should "extend DSL" in { + object Program { + sealed trait Foo1[A] + final case class Bar11(s: Int) extends Foo1[String] + + sealed trait Foo2[A] + final case class Bar21(s: String) extends Foo2[Int] + + type PRG = Foo1 :|: Foo2 :|: NilDSL + val PRG = DSL.Make[PRG] + + val program = for { + s <- Bar11(5).freek[PRG] + i <- Bar21(s).freek[PRG] + } yield (i) + } + + object OtherProgram { + import Program._ + + sealed trait Foo3[A] + case class Bar31[A](bar11: Foo1[A]) extends Foo3[A] + case class Bar32(i: Int) extends Foo3[String] + + type PRG = Foo3 :|: Foo2 :|: NilDSL + val PRG = DSL.Make[PRG] + + val copknat = CopKNat[Program.PRG.Cop].replace( + new (Foo1 ~> Foo3) { + def apply[A](foo1: Foo1[A]): Foo3[A] = Bar31(foo1) + } + ) + + val program = for { + i <- Program.program.compile(copknat) + s <- Bar32(i).freek[PRG] + } yield (s) + + } + + import Program._ + import OtherProgram._ + + val foo1Future = new (Foo1 ~> Future) { + def apply[A](a: Foo1[A]) = a match { + case Bar11(i) => Future { i.toString } + } + } + + val foo2Future = new (Foo2 ~> Future) { + def apply[A](a: Foo2[A]) = a match { + case Bar21(s) => Future { s.toInt } + } + } + + def foo3Future(foo1Nat: Foo1 ~> Future) = new (Foo3 ~> Future) { + def apply[A](a: Foo3[A]) = a match { + case Bar31(foo1) => foo1Nat(foo1) + case Bar32(i) => Future { i.toString } + } + } + + val interpreter = foo2Future :&: foo3Future(foo1Future) + + val fut = OtherProgram.program.interpret(interpreter) + + () + } + "freek" should "transpile" in { object Program { sealed trait Foo1[A] From a970322041c36687392f385bc3cff04facf704df Mon Sep 17 00:00:00 2001 From: mandubian Date: Sat, 22 Oct 2016 00:03:32 +0200 Subject: [PATCH 05/19] added freekit --- src/main/scala/Freekit.scala | 58 ++++++++++ src/test/scala/FreekitSpec.scala | 192 +++++++++++++++++++++++++++++++ 2 files changed, 250 insertions(+) create mode 100644 src/main/scala/Freekit.scala create mode 100644 src/test/scala/FreekitSpec.scala diff --git a/src/main/scala/Freekit.scala b/src/main/scala/Freekit.scala new file mode 100644 index 0000000..d92cccd --- /dev/null +++ b/src/main/scala/Freekit.scala @@ -0,0 +1,58 @@ +package freek + +import scala.reflect.macros.{ blackbox, whitebox } +import scala.reflect.macros.Context +import scala.language.experimental.macros +import scala.annotation.StaticAnnotation +import scala.annotation.compileTimeOnly + +import cats.free.Free + +import scala.language.implicitConversions + + +class Freekit[DSL0 <: DSL, C0[_] <: CopK[_]](val PRG: DSL.Make[DSL0, C0]) { + type PRG = PRG.DSL + type Cop[t] = PRG.Cop[t] + + implicit def liftFA[F[_], A](fa: F[A])( + implicit sub0: SubCop[In1[F, ?], Cop] + ): Free[Cop, A] = { + Freek.expand[In1[F, ?], Cop, A](Freek(fa))(sub0) + } + +} + +class Freekito[DSL0 <: DSL, C0[_] <: CopK[_]](val PRG: DSL.Make[DSL0, C0]) { + + type PRG = PRG.DSL + type Cop[t] = PRG.Cop[t] + type O <: Onion + + implicit def liftFGHA[F[_], G[_], HA, A](fga: F[G[HA]])( + implicit + ga: HKK.Aux[G[HA], A] + , sub0: SubCop[In1[F, ?], PRG.Cop] + , lifter2: Lifter2.Aux[G[HA], O, A] + , pointer: Pointer[O] + , mapper: Mapper[O] + , binder: Binder[O] + , traverser: Traverser[O] + ): OnionT[Free, PRG.Cop, O, A] = + OnionT.liftTHK(Freek.expand[In1[F, ?], PRG.Cop, G[HA]](Freek(fga))(sub0)) + + implicit def liftFA[F[_], A](fa: F[A])( + implicit + sub0: SubCop[In1[F, ?], PRG.Cop] + , pointer: Pointer[O] + , mapper: Mapper[O] + , binder: Binder[O] + , traverser: Traverser[O] + ): OnionT[Free, PRG.Cop, O, A] = + toOnionT0( + Freek.expand[In1[F, ?], PRG.Cop, A](Freek(fa))(sub0) + ).onionT[O] + +} + + diff --git a/src/test/scala/FreekitSpec.scala b/src/test/scala/FreekitSpec.scala new file mode 100644 index 0000000..bf4b65f --- /dev/null +++ b/src/test/scala/FreekitSpec.scala @@ -0,0 +1,192 @@ +package freek + + +/** + * Copyright 2014 Pascal Voitot (@mandubian) + */ +import org.scalatest._ + +import cats.free.{Free, Trampoline} +import cats.data.Xor +import cats.{~>, Id} + +import scala.concurrent._ +import scala.concurrent.duration._ + +// import cats.derived._, functor._, legacy._ +import cats.Functor +import cats.instances.future._ +import cats.instances.option._ +import cats.instances.list._ +import ExecutionContext.Implicits.global + +import freek._ + + +class FreekitSpec extends FlatSpec with Matchers { + + "Freek" should "macro" in { + + ////////////////////////////////////////////////////////////////////////// + // LOG DSL + sealed trait Log[A] + object Log { + case class Info(msg: String) extends Log[Unit] + } + + sealed trait Foo1[A] + object Foo1 { + final case class Bar1(a: Int) extends Foo1[Option[Int]] + } + + sealed trait Foo2[A] + object Foo2 { + final case class Bar21(a: Int) extends Foo2[Int] + final case object Bar22 extends Foo2[Int] + } + + + type PRG = Foo1 :|: Foo2 :|: Log :|: NilDSL + val PRG = DSL.Make[PRG] + + object M extends Freekit(PRG) { + val prg = for { + aOpt <- Foo1.Bar1(7) + _ <- Log.Info(s"aOpt:$aOpt") + a <- aOpt match { + case Some(a) => for { + a <- Foo2.Bar21(a) + _ <- Log.Info(s"a1:$a") + } yield (a) + case None => for { + a <- Foo2.Bar22 + _ <- Log.Info(s"a2:$a") + } yield (a) + } + } yield (a) + } + + object MO extends Freekito(PRG) { + type O = Option :&: Bulb + + val prg = for { + a <- Foo1.Bar1(7) + _ <- Log.Info(s"a:$a") + a <- Foo2.Bar21(a) + } yield (a) + } + + val foo1I = new (Foo1 ~> Future) { + import Foo1._ + + def apply[A](f: Foo1[A]): Future[A] = f match { + case Bar1(a) => Future(Some(a)) + + } + } + + val foo2I = new (Foo2 ~> Future) { + import Foo2._ + + def apply[A](f: Foo2[A]): Future[A] = f match { + case Bar21(a) => Future(a) + case Bar22 => Future(0) + } + } + + + val logI = new (Log ~> Future) { + def apply[A](a: Log[A]) = a match { + case Log.Info(msg) => + Future.successful(println(s"[info] $msg")) + } + } + + val f = M.prg.interpret(foo1I :&: foo2I :&: logI) + Await.result(f, 10.seconds) + + val f2 = MO.prg.value.interpret(foo1I :&: foo2I :&: logI) + Await.result(f2, 10.seconds) + } + + + "Freekit" should "special cases 4" in { + sealed trait Foo1[A] + final case class Bar11(s: Int) extends Foo1[Xor[String, List[Int]]] + final case class Bar12(s: List[Int]) extends Foo1[Xor[String, Option[Int]]] + + sealed trait Foo2[A] + final case class Bar21(s: Int) extends Foo1[Xor[Long, Option[List[Int]]]] + final case class Bar22(s: List[Int]) extends Foo1[Xor[Long, Option[Int]]] + + type PRG = Foo1 :|: Foo2 :|: NilDSL + val PRG = DSL.Make[PRG] + + object F1 extends Freekito(PRG) { + type O = Xor[String, ?] :&: Xor[Long, ?] :&: Option :&: Bulb + + val prg = for { + l1 <- Bar11(5).freek[PRG].onionX1[O] + _ <- Bar12(l1) + l2 <- Bar21(6).freek[PRG].onionX2[O] + _ <- Bar22(l2) + } yield (()) + } + } + + "Freekit" should "freek" in { + import Http._ + import DB._ + + object DBService extends Freekit(DSL.Make[Log.DSL :|: DB.DSL :|: NilDSL]) { + + /** the DSL.Make */ + def findById(id: String): Free[PRG.Cop, Xor[DBError, Entity]] = + for { + _ <- Log.debug("Searching for entity id:"+id) + res <- FindById(id) + _ <- Log.debug("Search result:"+res) + } yield (res) + } + + object HttpService extends Freekit(DSL.Make[Log.DSL :|: HttpInteract :|: HttpHandle :|: DBService.PRG]) { + + def handle(req: HttpReq): Free[PRG.Cop, HttpResp] = req.url match { + case "/foo" => + for { + _ <- Log.debug("/foo") + dbRes <- DBService.findById("foo").expand[PRG] + + resp <- HttpHandle.result( + dbRes match { + case Xor.Left(err) => HttpResp(status = InternalServerError) + case Xor.Right(e) => HttpResp(status = Ok, body = e.toString) + } + ) + } yield (resp) + + case _ => HttpHandle.result(HttpResp(status = InternalServerError)) + } + + def serve() : Free[PRG.Cop, Xor[RecvError, SendStatus]] = + for { + recv <- HttpInteract.receive() + _ <- Log.info("HttpReceived Request:"+recv) + res <- recv match { + case Xor.Left(err) => HttpInteract.stop(Xor.left(err)).freek[PRG] + + case Xor.Right(req) => + for { + resp <- handle(req) + _ <- Log.info("Sending Response:"+resp) + ack <- HttpInteract.respond(resp) + res <- if(ack == Ack) serve() + else HttpInteract.stop(Xor.right(ack)).freek[PRG] + } yield (res) + } + } yield (res) + + } + } + +} \ No newline at end of file From dfb86bbfb240d413fcc38c2ea2356d2eb09ccef5 Mon Sep 17 00:00:00 2001 From: mandubian Date: Tue, 25 Oct 2016 23:23:38 +0200 Subject: [PATCH 06/19] Fixes #14: no need of full cats --- build.sbt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/build.sbt b/build.sbt index 97cc572..7c87f22 100644 --- a/build.sbt +++ b/build.sbt @@ -13,11 +13,11 @@ lazy val commonSettings = Seq( , addCompilerPlugin("org.spire-math" %% "kind-projector" % "0.7.1") // , addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.full) , libraryDependencies ++= Seq( - "org.typelevel" %% "cats" % "0.7.0" - , "com.milessabin" % "si2712fix-library" % "1.2.0" cross CrossVersion.full - , "org.scalatest" % "scalatest_2.11" % "3.0.0" % "test" - , "org.typelevel" %% "discipline" % "0.4" % "test" - , "org.typelevel" %% "cats-laws" % "0.6.1" + "org.typelevel" %% "cats-free" % "0.7.0" + , "com.milessabin" % "si2712fix-library" % "1.2.0" cross CrossVersion.full + , "org.scalatest" % "scalatest_2.11" % "3.0.0" % "test" + // , "org.typelevel" %% "discipline" % "0.4" % "test" + // , "org.typelevel" %% "cats-laws" % "0.6.1" // , "org.scala-lang" % "scala-reflect" % scalaVersion.value % "provided" ) From 82392c1fea045482d8f01dfdd5c0d2d078a410b0 Mon Sep 17 00:00:00 2001 From: mandubian Date: Thu, 27 Oct 2016 17:53:13 +0200 Subject: [PATCH 07/19] bumped to 0.6.2 and added :&&: operator --- build.sbt | 2 +- src/main/scala/Interpreter.scala | 9 +++++++++ src/test/scala/AppSpec.scala | 6 ++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 7c87f22..d0c0162 100644 --- a/build.sbt +++ b/build.sbt @@ -1,6 +1,6 @@ lazy val commonSettings = Seq( organization := "com.projectseptember" - , version := "0.6.1" + , version := "0.6.2" , resolvers ++= Seq( Resolver.mavenLocal , Resolver.sonatypeRepo("releases") diff --git a/src/main/scala/Interpreter.scala b/src/main/scala/Interpreter.scala index 6fc9804..5d56e71 100644 --- a/src/main/scala/Interpreter.scala +++ b/src/main/scala/Interpreter.scala @@ -22,6 +22,15 @@ class Interpreter[C[_] <: CopK[_], R[_]]( // // TBD // ) + def :&&:[D[_] <: CopK[_]](f: Interpreter[D, R]): Interpreter[AppendK[C, D, ?], R] = new Interpreter( + new ~>[AppendK[C, D, ?], R] { + def apply[A](c: AppendK[C, D, A]): R[A] = c match { + case Aplk(l) => nat.nat(l) + case Aprk(r) => f.nat(r) + } + } + ) + def andThen[R2[_]](r2: R ~> R2): Interpreter[C, R2] = new Interpreter( nat andThen r2 ) diff --git a/src/test/scala/AppSpec.scala b/src/test/scala/AppSpec.scala index 055e2b0..ab0da16 100644 --- a/src/test/scala/AppSpec.scala +++ b/src/test/scala/AppSpec.scala @@ -777,10 +777,16 @@ class AppSpec extends FlatSpec with Matchers { } } + val fooInterpreters = foo2Future :&: logger2Future :&: repo2Future + val barInterpreters = bar2Future :&: logger2Future :&: repo2Future + val interpreters = foo2Future :&: logger2Future :&: bar2Future :&: repo2Future + val interpreters2 = logger2Future :&: fooInterpreters :&&: barInterpreters } val r = Await.result(Prg.prg.value.interpret(Prg.interpreters), 10.seconds) println("result:"+r) + val r2 = Await.result(Prg.prg.value.interpret(Prg.interpreters2), 10.seconds) + println("result:"+r2) } From 812cccf343301f7cf65763995c30505c6b121533 Mon Sep 17 00:00:00 2001 From: mandubian Date: Fri, 28 Oct 2016 16:09:41 +0200 Subject: [PATCH 08/19] version 0.6.2 + readme --- README.md | 69 ++++++++++++++++++++ src/test/scala/AppSpec.scala | 119 ++++++++++++++++++++++++++++++++++- 2 files changed, 187 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f743001..3bf29c6 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,13 @@ > All versions are published to bintray https://bintray.com/projectseptemberinc/ +
+### v0.6.1: + +- added `Freekit`/`Freekito` helpers to reduce `.freek` boilerplate in basic cases +- added `transpile` to flatten Free programs combining Free programs +- added `:&&:` operator to combine group of interpreters +
### v0.6.0: @@ -617,6 +624,17 @@ To make the difference between `:|:` and `:||:`, please remind the following: - `:||:` is like operator `++` for Scala `Seq`, it appends 2 (coproduct) sequences of DSL. +
+#### Combine group of interpreters with `:&&:` + +```scala +val fooInterpreters = barInterpreter :&: logInterpreter :|: repoInterpreter +val barInterpreters = fooInterpreter :&: logInterpreter :|: repoInterpreter + +val interpreters = fooInterpreters :&&: barInterpreters +``` + +- `:&&:` is like operator `++` for Scala `Seq`, it appends 2 sequences of interpreters.
#### Unstack results with `.peelRight` / `.peelRight2` / `.peelRight3` @@ -660,6 +678,57 @@ Instead of `Foo2(i).freek[PRG].onionT[O].peelRight2`, you can write `Foo2(i).fre Instead of `Foo2(i).freek[PRG].onionT[O].peelRight3`, you can write `Foo2(i).freek[PRG].onionT3[O]` +
+#### Bored adding `.free[PRG]` on each line? Use `Freekit` trick + +``` +type PRG = Foo1 :|: Foo2 :|: Log :|: NilDSL +val PRG = DSL.Make[PRG] + +// remark that you pass the value PRG here +object M extends Freekit(PRG) { + val prg = for { + aOpt <- Foo1.Bar1(7) + _ <- Log.Info(s"aOpt:$aOpt") + a <- aOpt match { + case Some(a) => for { + a <- Foo2.Bar21(a) + _ <- Log.Info(s"a1:$a") + } yield (a) + case None => for { + a <- Foo2.Bar22 + _ <- Log.Info(s"a2:$a") + } yield (a) + } + } yield (a) +} +``` + +This works in basic cases & naturally as soon as you have embedded `for-comprehension`, scalac inference makes it less efficient. + +
+#### Bored adding `.free[PRG].onionT[O]` on each line? Use `Freekito` trick + +``` +type PRG = Foo1 :|: Foo2 :|: Log :|: NilDSL +val PRG = DSL.Make[PRG] + +// remark that you pass the value PRG here +object MO extends Freekito(PRG) { + // you need to create this type O to reify the Onion + type O = Option :&: Bulb + + val prg = for { + a <- Foo1.Bar1(7) + _ <- Log.Info(s"a:$a") + a <- Foo2.Bar21(a) + } yield (a) +} +``` + +This works in basic cases & naturally as soon as you have embedded `for-comprehension`, scalac inference makes it less efficient. + +

## Reminding motivations diff --git a/src/test/scala/AppSpec.scala b/src/test/scala/AppSpec.scala index ab0da16..80688a5 100644 --- a/src/test/scala/AppSpec.scala +++ b/src/test/scala/AppSpec.scala @@ -965,7 +965,76 @@ class AppSpec extends FlatSpec with Matchers { val fut = OtherProgram.program.interpret(interpreter) () - } + } + + "freek" should "append DSL" in { + object Program { + sealed trait Foo1[A] + final case class Bar11(s: Int) extends Foo1[String] + + sealed trait Foo2[A] + final case class Bar21(s: String) extends Foo2[Int] + + type PRG = Foo1 :|: Foo2 :|: NilDSL + val PRG = DSL.Make[PRG] + + val program = for { + s <- Bar11(5).freek[PRG] + i <- Bar21(s).freek[PRG] + } yield (i) + } + + object OtherProgram { + import Program._ + + sealed trait Foo3[A] + case class Bar31[A](bar11: Foo1[A]) extends Foo3[A] + case class Bar32(i: Int) extends Foo3[String] + + type PRG = Foo3 :|: Foo2 :|: NilDSL + val PRG = DSL.Make[PRG] + + val copknat = CopKNat[Program.PRG.Cop].replace( + new (Foo1 ~> Foo3) { + def apply[A](foo1: Foo1[A]): Foo3[A] = Bar31(foo1) + } + ) + + val program = for { + i <- Program.program.compile(copknat) + s <- Bar32(i).freek[PRG] + } yield (s) + + } + + import Program._ + import OtherProgram._ + + val foo1Future = new (Foo1 ~> Future) { + def apply[A](a: Foo1[A]) = a match { + case Bar11(i) => Future { i.toString } + } + } + + val foo2Future = new (Foo2 ~> Future) { + def apply[A](a: Foo2[A]) = a match { + case Bar21(s) => Future { s.toInt } + } + } + + def foo3Future(foo1Nat: Foo1 ~> Future) = new (Foo3 ~> Future) { + def apply[A](a: Foo3[A]) = a match { + case Bar31(foo1) => foo1Nat(foo1) + case Bar32(i) => Future { i.toString } + } + } + + val interpreter = foo2Future :&: foo3Future(foo1Future) + + val fut = OtherProgram.program.interpret(interpreter) + + () + } "freek" should "transpile" in { object Program { @@ -1051,5 +1120,53 @@ class AppSpec extends FlatSpec with Matchers { println("r:"+r) } + // "freek" should "special case" in { + // import java.io.File + + // sealed trait KVS[A] + // object KVS { + // case class Get(key: String) extends KVS[String] + // case class Put(key: String, value: String) extends KVS[Unit] + // } + + // sealed trait FileIO[A] + // object FileIO { + // case class Get(name: String) extends FileIO[File] + // case class Delete(name: String) extends FileIO[Unit] + // } + + // val FileInterpreter = new (FileIO ~> Lambda[A => Future[Xor[Exception, A]]]) { + // override def apply[A](fa: FileIO[A]): Future[Xor[Exception, A]] = fa match { + // case FileIO.Get(name) => + // Future { + // Xor.right(new File(name)) + // } + + // case FileIO.Delete(name) => + // Future { + // new File(name).delete() + // Xor.right(()) + // } + // } + // } + + // val KVSInterpreter = new (KVS ~> Lambda[A => Future[Xor[Exception, A]]]) { + // def apply[A](a: KVS[A]): Future[Xor[Exception, A]] = a match { + // case KVS.Get(id) => + // Future { + // Xor.right("123") + // } + // case KVS.Put(id, value) => + // Future { + // Xor.right(()) + // } + // } + // } + + + // val interpreter = KVSInterpreter :&: toInterpreter(FileInterpreter) + + // } + } From 9a685e09aa7d359526f6312a419bb344d44069dd Mon Sep 17 00:00:00 2001 From: mandubian Date: Sun, 6 Nov 2016 21:24:47 +0100 Subject: [PATCH 09/19] readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3bf29c6..b570bef 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ > All versions are published to bintray https://bintray.com/projectseptemberinc/
-### v0.6.1: +### v0.6.1/2: - added `Freekit`/`Freekito` helpers to reduce `.freek` boilerplate in basic cases - added `transpile` to flatten Free programs combining Free programs From d3a0ffb76e74b172d16c83c5e02ff6b84fc670b1 Mon Sep 17 00:00:00 2001 From: mandubian Date: Mon, 7 Nov 2016 00:32:04 +0100 Subject: [PATCH 10/19] bumping v0.6.5: scala 2.11.8 & first 2.12 support with cats 0.8.0 --- build.sbt | 55 +++++--- src/main/scala/CopK.scala | 17 ++- src/main/scala/HasHoist.scala | 14 +- src/main/scala/OnionT.scala | 8 +- src/main/scala/package.scala | 2 +- src/test/scala/AppSpec.scala | 199 ++++++++++++++------------- src/test/scala/FreekitSpec.scala | 26 ++-- src/test/scala/LongCompileSpec.scala | 2 +- 8 files changed, 172 insertions(+), 151 deletions(-) diff --git a/build.sbt b/build.sbt index d0c0162..9cbd114 100644 --- a/build.sbt +++ b/build.sbt @@ -1,34 +1,51 @@ lazy val commonSettings = Seq( organization := "com.projectseptember" - , version := "0.6.2" + , version := "0.6.5" , resolvers ++= Seq( Resolver.mavenLocal , Resolver.sonatypeRepo("releases") , Resolver.sonatypeRepo("snapshots") ) , scalaVersion := "2.11.8" + , crossScalaVersions := Seq("2.11.8", "2.12.0") , bintrayOrganization := Some("projectseptemberinc") , licenses += ("Apache-2.0", url("http://www.apache.org/licenses/LICENSE-2.0")) - , addCompilerPlugin("com.milessabin" % "si2712fix-plugin" % "1.2.0" cross CrossVersion.full) - , addCompilerPlugin("org.spire-math" %% "kind-projector" % "0.7.1") - // , addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.full) - , libraryDependencies ++= Seq( - "org.typelevel" %% "cats-free" % "0.7.0" - , "com.milessabin" % "si2712fix-library" % "1.2.0" cross CrossVersion.full - , "org.scalatest" % "scalatest_2.11" % "3.0.0" % "test" - // , "org.typelevel" %% "discipline" % "0.4" % "test" - // , "org.typelevel" %% "cats-laws" % "0.6.1" - // , "org.scala-lang" % "scala-reflect" % scalaVersion.value % "provided" - ) - + , addCompilerPlugin("org.spire-math" %% "kind-projector" % "0.9.3" cross CrossVersion.binary) ) -lazy val root = (project in file(".")). - settings(commonSettings: _*). - settings( +def scalacOptionsVersion(scalaVersion: String) = { + Seq( + "-feature" + , "-language:higherKinds" + ) ++ (CrossVersion.partialVersion(scalaVersion) match { + case Some((2, scalaMajor)) if scalaMajor == 12 => Seq("-Ypartial-unification") + case _ => Seq() + }) +} + +lazy val root = (project in file(".")) + .settings(commonSettings: _*) + .settings( name := "freek", - scalacOptions ++= Seq( - "-feature" - , "-language:higherKinds" + scalacOptions ++= scalacOptionsVersion(scalaVersion.value) + ) + .settings( + libraryDependencies <<= (scalaVersion, libraryDependencies) { (ver, deps) => + deps ++ ( + CrossVersion.partialVersion(ver) match { + case Some((2, scalaMajor)) if scalaMajor == 11 => + Seq( + "org.typelevel" %% "cats-free" % "0.8.0" + , "org.scalatest" % "scalatest_2.11" % "3.0.0" % "test" + , compilerPlugin("com.milessabin" % "si2712fix-plugin" % "1.2.0" cross CrossVersion.full) + ) + case Some((2, scalaMajor)) if scalaMajor == 12 => + Seq( + "org.typelevel" % "cats-free_2.12.0-RC2" % "0.8.0" + , "org.scalatest" % "scalatest_2.12" % "3.0.0" % "test" + ) + } ) + } + ) diff --git a/src/main/scala/CopK.scala b/src/main/scala/CopK.scala index 3859143..1950cfe 100644 --- a/src/main/scala/CopK.scala +++ b/src/main/scala/CopK.scala @@ -1,7 +1,6 @@ package freek import cats.~> -import cats.data.Xor /** Higher-Kinded Coproduct (exactly like shapeless Coproduct but higher-kinded) @@ -603,7 +602,7 @@ object Flattener extends FlattenerLower{ type Out[t] = F[t] def flatten[A](tca: Free[In1[Free[F, ?], ?], A]): Free[F, A] = - tca.foldMapUnsafe(new (In1[Free[F, ?], ?] ~> Free[F, ?]) { + tca.foldMap(new (In1[Free[F, ?], ?] ~> Free[F, ?]) { def apply[A](in: In1[Free[F, ?], A]): Free[F, A] = in match { case In1(free) => free } @@ -617,7 +616,7 @@ object Flattener extends FlattenerLower{ type Out[t] = O[t] def flatten[A](tca: Free[In2[Free[F, ?], R, ?], A]): Free[O, A] = - tca.foldMapUnsafe(new (In2[Free[F, ?], R, ?] ~> Free[O, ?]) { + tca.foldMap(new (In2[Free[F, ?], R, ?] ~> Free[O, ?]) { def apply[A](in: In2[Free[F, ?], R, A]): Free[O, A] = in match { case In2l(free) => free.compile(new (F ~> O) { def apply[A](fa: F[A]): O[A] = ap(fa) @@ -636,7 +635,7 @@ object Flattener extends FlattenerLower{ type Out[t] = O2[t] def flatten[A](tca: Free[In3[Free[F, ?], M, R, ?], A]): Free[O2, A] = - tca.foldMapUnsafe(new (In3[Free[F, ?], M, R, ?] ~> Free[O2, ?]) { + tca.foldMap(new (In3[Free[F, ?], M, R, ?] ~> Free[O2, ?]) { def apply[A](in: In3[Free[F, ?], M, R, A]): Free[O2, A] = in match { case In3l(free) => free.compile(new (F ~> O2) { def apply[A](fa: F[A]): O2[A] = ap2(ap1(fa)) @@ -661,7 +660,7 @@ trait FlattenerLower extends FlattenerLower2 { type Out[t] = O[t] def flatten[A](tca: Free[In2[L, Free[F, ?], ?], A]): Free[O, A] = - tca.foldMapUnsafe(new (In2[L, Free[F, ?], ?] ~> Free[O, ?]) { + tca.foldMap(new (In2[L, Free[F, ?], ?] ~> Free[O, ?]) { def apply[A](in: In2[L, Free[F, ?], A]): Free[O, A] = in match { case In2l(l) => Free.liftF(pr.single(l)) @@ -680,7 +679,7 @@ trait FlattenerLower extends FlattenerLower2 { type Out[t] = O2[t] def flatten[A](tca: Free[In3[L, Free[F, ?], R, ?], A]): Free[O2, A] = - tca.foldMapUnsafe(new (In3[L, Free[F, ?], R, ?] ~> Free[O2, ?]) { + tca.foldMap(new (In3[L, Free[F, ?], R, ?] ~> Free[O2, ?]) { def apply[A](in: In3[L, Free[F, ?], R, A]): Free[O2, A] = in match { case In3l(l) => Free.liftF(ap(pr.single(l))) @@ -701,7 +700,7 @@ trait FlattenerLower extends FlattenerLower2 { def flatten[A](tca: Free[AppendK[L, R, ?], A]): Free[AppendK[O, R, ?], A] = - tca.foldMapUnsafe(new (AppendK[L, R, ?] ~> Free[AppendK[O, R, ?], ?]) { + tca.foldMap(new (AppendK[L, R, ?] ~> Free[AppendK[O, R, ?], ?]) { def apply[A](in: AppendK[L, R, A]): Free[AppendK[O, R, ?], A] = in match { case Aplk(l) => val free = Free.liftF(l) @@ -727,7 +726,7 @@ trait FlattenerLower2 { type Out[t] = O2[t] def flatten[A](tca: Free[In3[L, M, Free[F, ?], ?], A]): Free[O2, A] = - tca.foldMapUnsafe(new (In3[L, M, Free[F, ?], ?] ~> Free[O2, ?]) { + tca.foldMap(new (In3[L, M, Free[F, ?], ?] ~> Free[O2, ?]) { def apply[A](in: In3[L, M, Free[F, ?], A]): Free[O2, A] = in match { case In3l(l) => Free.liftF(pr2.single(l)) @@ -749,7 +748,7 @@ trait FlattenerLower2 { def flatten[A](tca: Free[AppendK[L, R, ?], A]): Free[AppendK[L, O, ?], A] = - tca.foldMapUnsafe(new (AppendK[L, R, ?] ~> Free[AppendK[L, O, ?], ?]) { + tca.foldMap(new (AppendK[L, R, ?] ~> Free[AppendK[L, O, ?], ?]) { def apply[A](in: AppendK[L, R, A]): Free[AppendK[L, O, ?], A] = in match { case Aplk(l) => Free.liftF(Aplk(l)) diff --git a/src/main/scala/HasHoist.scala b/src/main/scala/HasHoist.scala index b5be7e7..ae48a17 100644 --- a/src/main/scala/HasHoist.scala +++ b/src/main/scala/HasHoist.scala @@ -2,7 +2,7 @@ package freek import scala.language.higherKinds -import cats.data.{ OptionT, XorT, Xor } +import cats.data.{ OptionT, EitherT } import cats.Functor import cats.free._ @@ -13,10 +13,10 @@ trait HasHoist[M[_]] { def liftF[F[_] : Functor, A](f: F[A]): T[F, A] } -class XorHasHoist[A] extends HasHoist[λ[t => Xor[A, t]]] { - type T[F[_], B] = XorT[F, A, B] - def liftT[F[_], B](f: F[Xor[A, B]]): XorT[F, A, B] = XorT.apply(f) - def liftF[F[_] : Functor, B](f: F[B]): XorT[F, A, B] = XorT.right(f) +class EitherHasHoist[A] extends HasHoist[λ[t => Either[A, t]]] { + type T[F[_], B] = EitherT[F, A, B] + def liftT[F[_], B](f: F[Either[A, B]]): EitherT[F, A, B] = EitherT.apply(f) + def liftF[F[_] : Functor, B](f: F[B]): EitherT[F, A, B] = EitherT.right(f) } object HasHoist { @@ -30,8 +30,8 @@ object HasHoist { def liftF[F[_] : Functor, B](f: F[B]): OptionT[F, B] = OptionT.liftF(f) } - implicit def xorHasHoist[A]: HasHoist.Aux[λ[t => Xor[A, t]], λ[(f[_], b) => XorT[f, A, b]]] = - new XorHasHoist[A] + implicit def eitherHasHoist[A]: HasHoist.Aux[λ[t => Either[A, t]], λ[(f[_], b) => EitherT[f, A, b]]] = + new EitherHasHoist[A] } diff --git a/src/main/scala/OnionT.scala b/src/main/scala/OnionT.scala index fad97b3..2e3887e 100644 --- a/src/main/scala/OnionT.scala +++ b/src/main/scala/OnionT.scala @@ -2,7 +2,6 @@ package freek import cats.free.Free import cats.{Applicative, Functor, FlatMap, Monad, Traverse, Eq} -import cats.data.Xor /** The OnionT transformer to manipulate monadic stack of results */ @@ -188,7 +187,12 @@ trait OnionTInstances { override def map[A, B](fa: OnionT[TC, F, S, A])(f: A => B): OnionT[TC, F, S, B] = fa.map(f) - def tailRecM[A, B](a: A)(f: A => OnionT[TC, F, S, Either[A, B]]): OnionT[TC, F, S, B] = defaultTailRecM(a)(f) + // unsafe + def tailRecM[A, B](a: A)(f: A => OnionT[TC, F, S, Either[A, B]]): OnionT[TC, F, S, B] = + f(a).flatMap { + case Left(nextA) => tailRecM(nextA)(f) + case Right(b) => pure(b) + } } diff --git a/src/main/scala/package.scala b/src/main/scala/package.scala index 42921bf..a2334e4 100644 --- a/src/main/scala/package.scala +++ b/src/main/scala/package.scala @@ -50,7 +50,7 @@ package object freek extends LowerImplicits with HK { def interpret[F2[_] <: CopK[_], G[_]: Monad](i: Interpreter[F2, G])( implicit sub:SubCop[F, F2] - ): G[A] = free.foldMapUnsafe(new (F ~> G) { + ): G[A] = free.foldMap(new (F ~> G) { def apply[A](fa: F[A]): G[A] = i.nat(sub(fa)) }) diff --git a/src/test/scala/AppSpec.scala b/src/test/scala/AppSpec.scala index 80688a5..af22053 100644 --- a/src/test/scala/AppSpec.scala +++ b/src/test/scala/AppSpec.scala @@ -7,7 +7,7 @@ package freek import org.scalatest._ import cats.free.{Free, Trampoline} -import cats.data.Xor +// import cats.data.Either import cats.{~>, Id} import scala.concurrent._ @@ -18,6 +18,7 @@ import cats.Functor import cats.instances.future._ import cats.instances.option._ import cats.instances.list._ +import cats.instances.either._ import ExecutionContext.Implicits.global import freek._ @@ -55,7 +56,7 @@ object DB { case object NotFound extends DBError sealed trait DSL[A] - case class FindById(id: String) extends DSL[Xor[DBError, Entity]] + case class FindById(id: String) extends DSL[Either[DBError, Entity]] } @@ -117,14 +118,14 @@ object Http { case object NAck extends SendStatus sealed trait HttpInteract[A] - case object HttpReceive extends HttpInteract[Xor[RecvError, HttpReq]] + case object HttpReceive extends HttpInteract[Either[RecvError, HttpReq]] case class HttpRespond(data: HttpResp) extends HttpInteract[SendStatus] - case class Stop(error: Xor[RecvError, SendStatus]) extends HttpInteract[Xor[RecvError, SendStatus]] + case class Stop(error: Either[RecvError, SendStatus]) extends HttpInteract[Either[RecvError, SendStatus]] object HttpInteract { def receive() = HttpReceive def respond(data: HttpResp) = HttpRespond(data) - def stop(err: Xor[RecvError, SendStatus]) = Stop(err) + def stop(err: Either[RecvError, SendStatus]) = Stop(err) } sealed trait HttpHandle[A] @@ -160,7 +161,7 @@ class AppSpec extends FlatSpec with Matchers { val PRG = DSL.Make[PRG] /** the DSL.Make */ - def findById(id: String): Free[PRG.Cop, Xor[DBError, Entity]] = + def findById(id: String): Free[PRG.Cop, Either[DBError, Entity]] = for { _ <- Log.debug("Searching for entity id:"+id).freek[PRG] res <- FindById(id).freek[PRG] @@ -185,8 +186,8 @@ class AppSpec extends FlatSpec with Matchers { resp <- HttpHandle.result( dbRes match { - case Xor.Left(err) => HttpResp(status = InternalServerError) - case Xor.Right(e) => HttpResp(status = Ok, body = e.toString) + case Left(err) => HttpResp(status = InternalServerError) + case Right(e) => HttpResp(status = Ok, body = e.toString) } ).freek[PRG] } yield (resp) @@ -197,20 +198,20 @@ class AppSpec extends FlatSpec with Matchers { // server DSL.Make // this is the worst case: recursive call so need to help scalac a lot // but in classic cases, it should be much more straighforward - def serve() : Free[PRG.Cop, Xor[RecvError, SendStatus]] = + def serve() : Free[PRG.Cop, Either[RecvError, SendStatus]] = for { recv <- HttpInteract.receive().freek[PRG] _ <- Log.info("HttpReceived Request:"+recv).freek[PRG] res <- recv match { - case Xor.Left(err) => HttpInteract.stop(Xor.left(err)).freek[PRG] + case Left(err) => HttpInteract.stop(Left(err)).freek[PRG] - case Xor.Right(req) => + case Right(req) => for { resp <- handle(req) _ <- Log.info("Sending Response:"+resp).freek[PRG] ack <- HttpInteract.respond(resp).freek[PRG] res <- if(ack == Ack) serve() - else HttpInteract.stop(Xor.right(ack)).freek[PRG] + else HttpInteract.stop(Right(ack)).freek[PRG] } yield (res) } } yield (res) @@ -231,7 +232,7 @@ class AppSpec extends FlatSpec with Matchers { def apply[A](a: DB.DSL[A]) = a match { case DB.FindById(id) => println(s"DB Finding $id") - Xor.right(Map("id" -> id, "name" -> "toto")) + Right(Map("id" -> id, "name" -> "toto")) } } @@ -249,9 +250,9 @@ class AppSpec extends FlatSpec with Matchers { case Http.HttpReceive => if(i < 10000) { i+=1 - Xor.right(Http.GetReq("/foo")) + Right(Http.GetReq("/foo")) } else { - Xor.left(Http.ClientDisconnected) + Left(Http.ClientDisconnected) } case Http.HttpRespond(resp) => Http.Ack @@ -285,18 +286,18 @@ class AppSpec extends FlatSpec with Matchers { sealed trait Foo[A] final case class Bar(s: String) extends Foo[Option[Int]] - final case class Bar2(i: Int) extends Foo[Xor[String, Int]] + final case class Bar2(i: Int) extends Foo[Either[String, Int]] final case object Bar3 extends Foo[Unit] type PRG = Foo :|: Log.DSL :|: NilDSL val PRG = DSL.Make[PRG] val prg = for { - i <- Bar("5").freek[PRG].liftT[Option].liftF[Xor[String, ?]] - i <- Bar2(i).freek[PRG].liftF[Option].liftT[Xor[String, ?]] - _ <- Log.info("toto " + i).freek[PRG].liftF[Option].liftF[Xor[String, ?]] - _ <- Log.infoF("").expand[PRG].liftF[Option].liftF[Xor[String, ?]] - _ <- Bar3.freek[PRG].liftF[Option].liftF[Xor[String, ?]] + i <- Bar("5").freek[PRG].liftT[Option].liftF[Either[String, ?]] + i <- Bar2(i).freek[PRG].liftF[Option].liftT[Either[String, ?]] + _ <- Log.info("toto " + i).freek[PRG].liftF[Option].liftF[Either[String, ?]] + _ <- Log.infoF("").expand[PRG].liftF[Option].liftF[Either[String, ?]] + _ <- Bar3.freek[PRG].liftF[Option].liftF[Either[String, ?]] } yield (()) val logger2FutureSkip = new (Log.DSL ~> Future) { @@ -309,7 +310,7 @@ class AppSpec extends FlatSpec with Matchers { val foo2FutureSkip = new (Foo ~> Future) { def apply[A](a: Foo[A]) = a match { case Bar(s) => Future { Some(s.toInt) } // if you put None here, it stops prg before Log - case Bar2(i) => Future(Xor.right(i)) + case Bar2(i) => Future(Right(i)) case Bar3 => Future.successful(()) } } @@ -328,17 +329,17 @@ class AppSpec extends FlatSpec with Matchers { sealed trait Foo[A] final case class Foo1(s: String) extends Foo[List[Option[Int]]] - final case class Foo2(i: Int) extends Foo[Xor[String, Int]] + final case class Foo2(i: Int) extends Foo[Either[String, Int]] final case object Foo3 extends Foo[Unit] - final case class Foo4(i: Int) extends Foo[Xor[String, Option[Int]]] + final case class Foo4(i: Int) extends Foo[Either[String, Option[Int]]] sealed trait Bar[A] final case class Bar1(s: String) extends Bar[Option[String]] - final case class Bar2(i: Int) extends Bar[Xor[String, String]] + final case class Bar2(i: Int) extends Bar[Either[String, String]] type PRG2 = Bar :|: Log.DSL :|: NilDSL - type O = List :&: Xor[String, ?] :&: Option :&: Bulb + type O = List :&: Either[String, ?] :&: Option :&: Bulb type PRG = Foo :|: Log.DSL :|: PRG2 val PRG = DSL.Make[PRG] @@ -362,16 +363,16 @@ class AppSpec extends FlatSpec with Matchers { val foo2Future = new (Foo ~> Future) { def apply[A](a: Foo[A]) = a match { case Foo1(s) => Future { List(Some(s.toInt)) } // if you put None here, it stops prg before Log - case Foo2(i) => Future(Xor.right(i)) + case Foo2(i) => Future(Right(i)) case Foo3 => Future.successful(()) - case Foo4(i) => Future.successful(Xor.right(Some(i))) + case Foo4(i) => Future.successful(Right(Some(i))) } } val bar2Future = new (Bar ~> Future) { def apply[A](a: Bar[A]) = a match { case Bar1(s) => Future { Some(s) } // if you put None here, it stops prg before Log - case Bar2(i) => Future(Xor.right(i.toString)) + case Bar2(i) => Future(Right(i.toString)) } } @@ -389,17 +390,17 @@ class AppSpec extends FlatSpec with Matchers { sealed trait Foo[A] final case class Foo1(s: String) extends Foo[Option[Int]] - final case class Foo2(i: Int) extends Foo[Xor[String, Int]] + final case class Foo2(i: Int) extends Foo[Either[String, Int]] final case object Foo3 extends Foo[Unit] - final case class Foo4(i: Int) extends Foo[Xor[String, Option[Int]]] + final case class Foo4(i: Int) extends Foo[Either[String, Option[Int]]] sealed trait Bar[A] final case class Bar1(s: String) extends Bar[List[Option[String]]] - final case class Bar2(i: Int) extends Bar[Xor[String, String]] + final case class Bar2(i: Int) extends Bar[Either[String, String]] type PRG2 = Bar :|: Log.DSL :|: NilDSL - type O = List :&: Xor[String, ?] :&: Bulb + type O = List :&: Either[String, ?] :&: Bulb type PRG = Foo :|: Log.DSL :|: PRG2 val PRG = DSL.Make[PRG] @@ -426,16 +427,16 @@ class AppSpec extends FlatSpec with Matchers { val foo2Future = new (Foo ~> Future) { def apply[A](a: Foo[A]) = a match { case Foo1(s) => Future { Some(s.toInt) } // if you put None here, it stops prg before Log - case Foo2(i) => Future(Xor.right(i)) + case Foo2(i) => Future(Right(i)) case Foo3 => Future.successful(()) - case Foo4(i) => Future.successful(Xor.right(Some(i))) + case Foo4(i) => Future.successful(Right(Some(i))) } } val bar2Future = new (Bar ~> Future) { def apply[A](a: Bar[A]) = a match { case Bar1(s) => Future { List(Some(s)) } // if you put None here, it stops prg before Log - case Bar2(i) => Future(Xor.right(i.toString)) + case Bar2(i) => Future(Right(i.toString)) } } @@ -453,17 +454,17 @@ class AppSpec extends FlatSpec with Matchers { sealed trait Foo[A] final case class Foo1(s: String) extends Foo[Option[Int]] - final case class Foo2(i: Int) extends Foo[Xor[String, Int]] + final case class Foo2(i: Int) extends Foo[Either[String, Int]] final case object Foo3 extends Foo[Unit] - final case class Foo4(i: Int) extends Foo[Xor[String, Option[Int]]] + final case class Foo4(i: Int) extends Foo[Either[String, Option[Int]]] sealed trait Bar[A] final case class Bar1(s: String) extends Bar[List[Option[String]]] - final case class Bar2(i: Int) extends Bar[Xor[String, String]] + final case class Bar2(i: Int) extends Bar[Either[String, String]] type PRG2 = Bar :|: Log.DSL :|: NilDSL - type O = List :&: Xor[String, ?] :&: Option :&: Bulb + type O = List :&: Either[String, ?] :&: Option :&: Bulb type PRG = Foo :|: Log.DSL :|: PRG2 val PRG = DSL.Make[PRG] @@ -493,16 +494,16 @@ class AppSpec extends FlatSpec with Matchers { val foo2Future = new (Foo ~> Future) { def apply[A](a: Foo[A]) = a match { case Foo1(s) => Future { Some(s.toInt) } // if you put None here, it stops prg before Log - case Foo2(i) => Future(Xor.right(i)) + case Foo2(i) => Future(Right(i)) case Foo3 => Future.successful(()) - case Foo4(i) => Future.successful(Xor.right(Some(i))) + case Foo4(i) => Future.successful(Right(Some(i))) } } val bar2Future = new (Bar ~> Future) { def apply[A](a: Bar[A]) = a match { case Bar1(s) => Future { List(Some(s)) } // if you put None here, it stops prg before Log - case Bar2(i) => Future(Xor.right(i.toString)) + case Bar2(i) => Future(Right(i.toString)) } } @@ -525,17 +526,17 @@ class AppSpec extends FlatSpec with Matchers { sealed trait Foo[A] final case class Foo1(s: String) extends Foo[List[Option[Int]]] - final case class Foo2(i: Int) extends Foo[Xor[String, Int]] + final case class Foo2(i: Int) extends Foo[Either[String, Int]] final case object Foo3 extends Foo[Unit] - final case class Foo4(i: Int) extends Foo[Xor[String, Option[Int]]] + final case class Foo4(i: Int) extends Foo[Either[String, Option[Int]]] sealed trait Bar[A] final case class Bar1(s: String) extends Bar[Option[String]] - final case class Bar2(i: Int) extends Bar[Xor[String, String]] + final case class Bar2(i: Int) extends Bar[Either[String, String]] type PRG2 = Bar :|: Log.DSL :|: NilDSL - type O = List :&: Xor[String, ?] :&: Option :&: Bulb + type O = List :&: Either[String, ?] :&: Option :&: Bulb type PRG = Foo :|: Log.DSL :|: KVS[String, Int, ?] :|: PRG2 val PRG = DSL.Make[PRG] @@ -561,16 +562,16 @@ class AppSpec extends FlatSpec with Matchers { val foo2Future = new (Foo ~> Future) { def apply[A](a: Foo[A]) = a match { case Foo1(s) => Future { List(Some(s.toInt)) } // if you put None here, it stops prg before Log - case Foo2(i) => Future(Xor.right(i)) + case Foo2(i) => Future(Right(i)) case Foo3 => Future.successful(()) - case Foo4(i) => Future.successful(Xor.right(Some(i))) + case Foo4(i) => Future.successful(Right(Some(i))) } } val bar2Future = new (Bar ~> Future) { def apply[A](a: Bar[A]) = a match { case Bar1(s) => Future { Some(s) } // if you put None here, it stops prg before Log - case Bar2(i) => Future(Xor.right(i.toString)) + case Bar2(i) => Future(Right(i.toString)) } } @@ -596,19 +597,19 @@ class AppSpec extends FlatSpec with Matchers { sealed trait Bar[A] final case class Bar1(s: String) extends Bar[List[Option[String]]] - final case class Bar2(i: Int) extends Bar[Xor[String, String]] + final case class Bar2(i: Int) extends Bar[Either[String, String]] type PRG2 = Bar :|: Log.DSL :|: NilDSL - type O = List :&: Xor[String, ?] :&: Option :&: Bulb + type O = List :&: Either[String, ?] :&: Option :&: Bulb type PRG = Foo :|: Log.DSL :|: PRG2 val PRG = DSL.Make[PRG] - val f: OnionT[Free, PRG.Cop, List :&: Xor[String, ?] :&: Bulb, Option[Int]] = + val f: OnionT[Free, PRG.Cop, List :&: Either[String, ?] :&: Bulb, Option[Int]] = Foo1("5") .freek[PRG] - .onionT[Xor[String, ?] :&: Option :&: Bulb] + .onionT[Either[String, ?] :&: Option :&: Bulb] .wrap[List] .peelRight @@ -622,17 +623,17 @@ class AppSpec extends FlatSpec with Matchers { sealed trait Foo[A] final case class Foo1(s: String) extends Foo[List[Option[Int]]] - final case class Foo2(i: Int) extends Foo[Xor[String, Int]] + final case class Foo2(i: Int) extends Foo[Either[String, Int]] final case object Foo3 extends Foo[Unit] - final case class Foo4(i: Int) extends Foo[Xor[String, Option[Int]]] + final case class Foo4(i: Int) extends Foo[Either[String, Option[Int]]] sealed trait Bar[A] final case class Bar1(s: String) extends Bar[Option[String]] - final case class Bar2(i: Int) extends Bar[Xor[String, String]] + final case class Bar2(i: Int) extends Bar[Either[String, String]] type PRG2 = Bar :|: Log.DSL :|: NilDSL - type O = List :&: Xor[String, ?] :&: Option :&: Bulb + type O = List :&: Either[String, ?] :&: Option :&: Bulb type PRG = Foo :|: Log.DSL :|: PRG2 val PRG = DSL.Make[PRG] @@ -656,16 +657,16 @@ class AppSpec extends FlatSpec with Matchers { val foo2Future = new (Foo ~> Future) { def apply[A](a: Foo[A]) = a match { case Foo1(s) => Future { List(Some(s.toInt)) } // if you put None here, it stops prg before Log - case Foo2(i) => Future(Xor.right(i)) + case Foo2(i) => Future(Right(i)) case Foo3 => Future.successful(()) - case Foo4(i) => Future.successful(Xor.right(Some(i))) + case Foo4(i) => Future.successful(Right(Some(i))) } } val bar2Future = new (Bar ~> Future) { def apply[A](a: Bar[A]) = a match { case Bar1(s) => Future { Some(s) } // if you put None here, it stops prg before Log - case Bar2(i) => Future(Xor.right(i.toString)) + case Bar2(i) => Future(Right(i.toString)) } } @@ -683,13 +684,13 @@ class AppSpec extends FlatSpec with Matchers { sealed trait RepoF[A] sealed trait Repo[A] - case class Query(no: String) extends Repo[Xor[String, Account]] - case class Store(account: Account) extends Repo[Xor[String, Account]] - case class Delete(no: String) extends Repo[Xor[String, Unit]] + case class Query(no: String) extends Repo[Either[String, Account]] + case class Store(account: Account) extends Repo[Either[String, Account]] + case class Delete(no: String) extends Repo[Either[String, Unit]] object Repo { type PRG = Repo :|: NilDSL - type O = Xor[String, ?] :&: Bulb + type O = Either[String, ?] :&: Bulb } def query(no: String) = Query(no) @@ -706,9 +707,9 @@ class AppSpec extends FlatSpec with Matchers { trait FooLayer extends RepositoryLayer { sealed trait Foo[A] final case class Foo1(s: String) extends Foo[List[Option[Int]]] - final case class Foo2(i: Int) extends Foo[Xor[String, Int]] + final case class Foo2(i: Int) extends Foo[Either[String, Int]] final case object Foo3 extends Foo[Unit] - final case class Foo4(i: Int) extends Foo[Xor[String, Option[Int]]] + final case class Foo4(i: Int) extends Foo[Either[String, Option[Int]]] object Foo { type PRG = Foo :|: Log.DSL :|: Repo.PRG @@ -719,7 +720,7 @@ class AppSpec extends FlatSpec with Matchers { sealed trait Bar[A] final case class Bar1(s: String) extends Bar[Option[String]] - final case class Bar2(i: Int) extends Bar[Xor[String, String]] + final case class Bar2(i: Int) extends Bar[Either[String, String]] object Bar { type PRG = Bar :|: Log.DSL :|: Repo.PRG @@ -731,7 +732,7 @@ class AppSpec extends FlatSpec with Matchers { extends FooLayer with BarLayer { - type O = List :&: Xor[String, ?] :&: Option :&: Bulb + type O = List :&: Either[String, ?] :&: Option :&: Bulb type PRG = Log.DSL :|: Bar.PRG :||: Foo.PRG val PRG = DSL.Make[PRG] @@ -756,24 +757,24 @@ class AppSpec extends FlatSpec with Matchers { val foo2Future = new (Foo ~> Future) { def apply[A](a: Foo[A]) = a match { case Foo1(s) => Future { println(s); List(Some(s.toInt)) } // if you put None here, it stops prg before Log - case Foo2(i) => Future(Xor.right(i)) + case Foo2(i) => Future(Right(i)) case Foo3 => Future.successful(()) - case Foo4(i) => Future.successful(Xor.right(Some(i))) + case Foo4(i) => Future.successful(Right(Some(i))) } } val bar2Future = new (Bar ~> Future) { def apply[A](a: Bar[A]) = a match { case Bar1(s) => Future { Some(s) } // if you put None here, it stops prg before Log - case Bar2(i) => Future(Xor.right(i.toString)) + case Bar2(i) => Future(Right(i.toString)) } } val repo2Future = new (Repo ~> Future) { def apply[A](a: Repo[A]) = a match { - case Query(s) => Future { Xor.right(new Account {}) } - case Store(acc) => Future { Xor.right(new Account {}) } - case Delete(no) => Future { Xor.right(()) } + case Query(s) => Future { Right(new Account {}) } + case Store(acc) => Future { Right(new Account {}) } + case Delete(no) => Future { Right(()) } } } @@ -827,15 +828,15 @@ class AppSpec extends FlatSpec with Matchers { final case class Bar22(s: Int) extends Foo2[List[Option[Int]]] sealed trait Foo3[A] - final case class Bar31(s: Long) extends Foo3[Xor[String, Long]] - final case class Bar32(s: Float) extends Foo3[Xor[String, List[Float]]] - final case class Bar33(s: Double) extends Foo3[Xor[String, Option[Boolean]]] + final case class Bar31(s: Long) extends Foo3[Either[String, Long]] + final case class Bar32(s: Float) extends Foo3[Either[String, List[Float]]] + final case class Bar33(s: Double) extends Foo3[Either[String, Option[Boolean]]] type PRG = Foo1 :|: Foo2 :|: Foo3 :|: NilDSL val PRG = DSL.Make[PRG] - type O = Xor[String, ?] :&: List :&: Option :&: Bulb + type O = Either[String, ?] :&: List :&: Option :&: Bulb - val f1: Free[PRG.Cop, Xor[String, List[Option[Unit]]]] = (for { + val f1: Free[PRG.Cop, Either[String, List[Option[Unit]]]] = (for { i <- Bar1(3).freek[PRG].onionT[O] i <- Bar21(i).freek[PRG].onionT[O] i <- Bar22(i).freek[PRG].onionT[O] @@ -855,17 +856,17 @@ class AppSpec extends FlatSpec with Matchers { final case class Bar22(s: Int) extends Foo2[List[Option[Int]]] sealed trait Foo3[A] - final case class Bar31(s: Int) extends Foo3[Xor[String, Long]] - final case class Bar32(s: Float) extends Foo3[Xor[String, List[Float]]] - final case class Bar33(s: Double) extends Foo3[Xor[String, Option[Boolean]]] - final case class Bar34(s: Double) extends Foo3[Xor[String, List[Option[Boolean]]]] + final case class Bar31(s: Int) extends Foo3[Either[String, Long]] + final case class Bar32(s: Float) extends Foo3[Either[String, List[Float]]] + final case class Bar33(s: Double) extends Foo3[Either[String, Option[Boolean]]] + final case class Bar34(s: Double) extends Foo3[Either[String, List[Option[Boolean]]]] type PRG = Foo1 :|: Foo2 :|: Foo3 :|: NilDSL val PRG = DSL.Make[PRG] - type O = Xor[String, ?] :&: List :&: Option :&: Bulb + type O = Either[String, ?] :&: List :&: Option :&: Bulb // ugly head & get :D - val f1: Free[PRG.Cop, Xor[String, String]] = (for { + val f1: Free[PRG.Cop, Either[String, String]] = (for { i <- Bar1(3).freek[PRG].onionT2[O] i <- Bar21(i.head.get).freek[PRG].onionT2[O] i <- Bar22(i.head.get).freek[PRG].onionT2[O] @@ -878,16 +879,16 @@ class AppSpec extends FlatSpec with Matchers { "freek" should "special cases 4" in { sealed trait Foo1[A] - final case class Bar11(s: Int) extends Foo1[Xor[String, List[Int]]] - final case class Bar12(s: List[Int]) extends Foo1[Xor[String, Option[Int]]] + final case class Bar11(s: Int) extends Foo1[Either[String, List[Int]]] + final case class Bar12(s: List[Int]) extends Foo1[Either[String, Option[Int]]] sealed trait Foo2[A] - final case class Bar21(s: Int) extends Foo1[Xor[Long, Option[List[Int]]]] - final case class Bar22(s: List[Int]) extends Foo1[Xor[Long, Option[Int]]] + final case class Bar21(s: Int) extends Foo1[Either[Long, Option[List[Int]]]] + final case class Bar22(s: List[Int]) extends Foo1[Either[Long, Option[Int]]] type PRG = Foo1 :|: Foo2 :|: NilDSL val PRG = DSL.Make[PRG] - type O = Xor[String, ?] :&: Xor[Long, ?] :&: Option :&: Bulb + type O = Either[String, ?] :&: Either[Long, ?] :&: Option :&: Bulb val f1: OnionT[Free, PRG.Cop, O, Unit] = for { l1 <- Bar11(5).freek[PRG].onionX1[O] @@ -1135,30 +1136,30 @@ class AppSpec extends FlatSpec with Matchers { // case class Delete(name: String) extends FileIO[Unit] // } - // val FileInterpreter = new (FileIO ~> Lambda[A => Future[Xor[Exception, A]]]) { - // override def apply[A](fa: FileIO[A]): Future[Xor[Exception, A]] = fa match { + // val FileInterpreter = new (FileIO ~> Lambda[A => Future[Either[Exception, A]]]) { + // override def apply[A](fa: FileIO[A]): Future[Either[Exception, A]] = fa match { // case FileIO.Get(name) => // Future { - // Xor.right(new File(name)) + // Right(new File(name)) // } // case FileIO.Delete(name) => // Future { // new File(name).delete() - // Xor.right(()) + // Right(()) // } // } // } - // val KVSInterpreter = new (KVS ~> Lambda[A => Future[Xor[Exception, A]]]) { - // def apply[A](a: KVS[A]): Future[Xor[Exception, A]] = a match { + // val KVSInterpreter = new (KVS ~> Lambda[A => Future[Either[Exception, A]]]) { + // def apply[A](a: KVS[A]): Future[Either[Exception, A]] = a match { // case KVS.Get(id) => // Future { - // Xor.right("123") + // Right("123") // } // case KVS.Put(id, value) => // Future { - // Xor.right(()) + // Right(()) // } // } // } diff --git a/src/test/scala/FreekitSpec.scala b/src/test/scala/FreekitSpec.scala index bf4b65f..bf265c8 100644 --- a/src/test/scala/FreekitSpec.scala +++ b/src/test/scala/FreekitSpec.scala @@ -7,7 +7,6 @@ package freek import org.scalatest._ import cats.free.{Free, Trampoline} -import cats.data.Xor import cats.{~>, Id} import scala.concurrent._ @@ -18,6 +17,7 @@ import cats.Functor import cats.instances.future._ import cats.instances.option._ import cats.instances.list._ +import cats.instances.either._ import ExecutionContext.Implicits.global import freek._ @@ -112,18 +112,18 @@ class FreekitSpec extends FlatSpec with Matchers { "Freekit" should "special cases 4" in { sealed trait Foo1[A] - final case class Bar11(s: Int) extends Foo1[Xor[String, List[Int]]] - final case class Bar12(s: List[Int]) extends Foo1[Xor[String, Option[Int]]] + final case class Bar11(s: Int) extends Foo1[Either[String, List[Int]]] + final case class Bar12(s: List[Int]) extends Foo1[Either[String, Option[Int]]] sealed trait Foo2[A] - final case class Bar21(s: Int) extends Foo1[Xor[Long, Option[List[Int]]]] - final case class Bar22(s: List[Int]) extends Foo1[Xor[Long, Option[Int]]] + final case class Bar21(s: Int) extends Foo1[Either[Long, Option[List[Int]]]] + final case class Bar22(s: List[Int]) extends Foo1[Either[Long, Option[Int]]] type PRG = Foo1 :|: Foo2 :|: NilDSL val PRG = DSL.Make[PRG] object F1 extends Freekito(PRG) { - type O = Xor[String, ?] :&: Xor[Long, ?] :&: Option :&: Bulb + type O = Either[String, ?] :&: Either[Long, ?] :&: Option :&: Bulb val prg = for { l1 <- Bar11(5).freek[PRG].onionX1[O] @@ -141,7 +141,7 @@ class FreekitSpec extends FlatSpec with Matchers { object DBService extends Freekit(DSL.Make[Log.DSL :|: DB.DSL :|: NilDSL]) { /** the DSL.Make */ - def findById(id: String): Free[PRG.Cop, Xor[DBError, Entity]] = + def findById(id: String): Free[PRG.Cop, Either[DBError, Entity]] = for { _ <- Log.debug("Searching for entity id:"+id) res <- FindById(id) @@ -159,8 +159,8 @@ class FreekitSpec extends FlatSpec with Matchers { resp <- HttpHandle.result( dbRes match { - case Xor.Left(err) => HttpResp(status = InternalServerError) - case Xor.Right(e) => HttpResp(status = Ok, body = e.toString) + case Left(err) => HttpResp(status = InternalServerError) + case Right(e) => HttpResp(status = Ok, body = e.toString) } ) } yield (resp) @@ -168,20 +168,20 @@ class FreekitSpec extends FlatSpec with Matchers { case _ => HttpHandle.result(HttpResp(status = InternalServerError)) } - def serve() : Free[PRG.Cop, Xor[RecvError, SendStatus]] = + def serve() : Free[PRG.Cop, Either[RecvError, SendStatus]] = for { recv <- HttpInteract.receive() _ <- Log.info("HttpReceived Request:"+recv) res <- recv match { - case Xor.Left(err) => HttpInteract.stop(Xor.left(err)).freek[PRG] + case Left(err) => HttpInteract.stop(Left(err)).freek[PRG] - case Xor.Right(req) => + case Right(req) => for { resp <- handle(req) _ <- Log.info("Sending Response:"+resp) ack <- HttpInteract.respond(resp) res <- if(ack == Ack) serve() - else HttpInteract.stop(Xor.right(ack)).freek[PRG] + else HttpInteract.stop(Right(ack)).freek[PRG] } yield (res) } } yield (res) diff --git a/src/test/scala/LongCompileSpec.scala b/src/test/scala/LongCompileSpec.scala index 647ba9f..5a101fd 100644 --- a/src/test/scala/LongCompileSpec.scala +++ b/src/test/scala/LongCompileSpec.scala @@ -7,7 +7,6 @@ package freek import org.scalatest._ import cats.free.{Free, Trampoline} -import cats.data.Xor import cats.{~>, Id} import scala.concurrent._ @@ -18,6 +17,7 @@ import cats.Functor import cats.instances.future._ import cats.instances.option._ import cats.instances.list._ +import cats.instances.either._ import ExecutionContext.Implicits.global import freek._ From 82ef3fa5c69a919beb6503e6873fd1385035b489 Mon Sep 17 00:00:00 2001 From: mandubian Date: Mon, 7 Nov 2016 00:33:32 +0100 Subject: [PATCH 11/19] readme for v0.6.5 --- README.md | 7 +++++++ build.sbt | 33 ++++++++++++++++----------------- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index b570bef..56ad636 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,13 @@ > All versions are published to bintray https://bintray.com/projectseptemberinc/ +
+### v0.6.5: + +- first scala 2.12 support +- cross-compiling 2.11.8 & 2.12 +- depends on cats 0.8.0 +
### v0.6.1/2: diff --git a/build.sbt b/build.sbt index 9cbd114..48d6b44 100644 --- a/build.sbt +++ b/build.sbt @@ -31,21 +31,20 @@ lazy val root = (project in file(".")) ) .settings( libraryDependencies <<= (scalaVersion, libraryDependencies) { (ver, deps) => - deps ++ ( - CrossVersion.partialVersion(ver) match { - case Some((2, scalaMajor)) if scalaMajor == 11 => - Seq( - "org.typelevel" %% "cats-free" % "0.8.0" - , "org.scalatest" % "scalatest_2.11" % "3.0.0" % "test" - , compilerPlugin("com.milessabin" % "si2712fix-plugin" % "1.2.0" cross CrossVersion.full) - ) - case Some((2, scalaMajor)) if scalaMajor == 12 => - Seq( - "org.typelevel" % "cats-free_2.12.0-RC2" % "0.8.0" - , "org.scalatest" % "scalatest_2.12" % "3.0.0" % "test" - ) - } - ) - } - + deps ++ ( + CrossVersion.partialVersion(ver) match { + case Some((2, scalaMajor)) if scalaMajor == 11 => + Seq( + "org.typelevel" %% "cats-free" % "0.8.0" + , "org.scalatest" % "scalatest_2.11" % "3.0.0" % "test" + , compilerPlugin("com.milessabin" % "si2712fix-plugin" % "1.2.0" cross CrossVersion.full) + ) + case Some((2, scalaMajor)) if scalaMajor == 12 => + Seq( + "org.typelevel" % "cats-free_2.12.0-RC2" % "0.8.0" + , "org.scalatest" % "scalatest_2.12" % "3.0.0" % "test" + ) + } + ) + } ) From 432c1644e25886a298134d473b758b15b7d32a38 Mon Sep 17 00:00:00 2001 From: mandubian Date: Mon, 7 Nov 2016 00:39:36 +0100 Subject: [PATCH 12/19] readme --- README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 56ad636..ec02d3a 100644 --- a/README.md +++ b/README.md @@ -91,14 +91,12 @@ Freek is just a few helpers & tricks to make it straightforward to manipulate Fr ``` # in build.sbt -scalaVersion := "2.11.8" +scalaVersion := "2.12.0" // (or 2.11.8) resolvers += Resolver.bintrayRepo("projectseptemberinc", "maven") libraryDependencies ++= Seq( - "com.projectseptember" %% "freek" % "0.6.0" // with cats-0.7.0 -// "com.projectseptember" %% "freek" % "0.6.0_cats-0.4.1" // with cats-0.4.1 -// "com.projectseptember" %% "freek" % "0.6.0_cats-0.6.1" // with cats-0.6.1 + "com.projectseptember" %% "freek" % "0.6.5" , "org.spire-math" %% "kind-projector" % "0.7.1" , "com.milessabin" %% "si2712fix-plugin" % "1.2.0" ) From aaee2db9ab42e4ac0ffda45bd18d602e2287206a Mon Sep 17 00:00:00 2001 From: dwhitney Date: Tue, 8 Nov 2016 15:37:37 -0500 Subject: [PATCH 13/19] added compiler flag for partial unification to setup --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index ec02d3a..7ee2ca6 100644 --- a/README.md +++ b/README.md @@ -95,6 +95,8 @@ scalaVersion := "2.12.0" // (or 2.11.8) resolvers += Resolver.bintrayRepo("projectseptemberinc", "maven") +scalacOptions := Seq("-Ypartial-unification") //if running 2.12 + libraryDependencies ++= Seq( "com.projectseptember" %% "freek" % "0.6.5" , "org.spire-math" %% "kind-projector" % "0.7.1" From f9e2a8e0883c783dca6c50f1eeb60f01800a7ad9 Mon Sep 17 00:00:00 2001 From: Dragisa Krsmanovic Date: Thu, 10 Nov 2016 14:13:18 -0800 Subject: [PATCH 14/19] Upgrade to cats 0.8.1 --- .gitignore | 2 +- build.sbt | 32 +++++++++++--------------------- project/build.properties | 2 +- 3 files changed, 13 insertions(+), 23 deletions(-) diff --git a/.gitignore b/.gitignore index 6da9171..8766f35 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ - target/ lib_managed/ src_managed/ project/boot/ .history .cache +.idea diff --git a/build.sbt b/build.sbt index 48d6b44..aa4a8e8 100644 --- a/build.sbt +++ b/build.sbt @@ -4,13 +4,12 @@ lazy val commonSettings = Seq( , resolvers ++= Seq( Resolver.mavenLocal , Resolver.sonatypeRepo("releases") - , Resolver.sonatypeRepo("snapshots") - ) + , Resolver.sonatypeRepo("snapshots")) , scalaVersion := "2.11.8" , crossScalaVersions := Seq("2.11.8", "2.12.0") , bintrayOrganization := Some("projectseptemberinc") , licenses += ("Apache-2.0", url("http://www.apache.org/licenses/LICENSE-2.0")) - , addCompilerPlugin("org.spire-math" %% "kind-projector" % "0.9.3" cross CrossVersion.binary) + , addCompilerPlugin("org.spire-math" % "kind-projector" % "0.9.3" cross CrossVersion.binary) ) def scalacOptionsVersion(scalaVersion: String) = { @@ -19,7 +18,7 @@ def scalacOptionsVersion(scalaVersion: String) = { , "-language:higherKinds" ) ++ (CrossVersion.partialVersion(scalaVersion) match { case Some((2, scalaMajor)) if scalaMajor == 12 => Seq("-Ypartial-unification") - case _ => Seq() + case _ => Nil }) } @@ -30,21 +29,12 @@ lazy val root = (project in file(".")) scalacOptions ++= scalacOptionsVersion(scalaVersion.value) ) .settings( - libraryDependencies <<= (scalaVersion, libraryDependencies) { (ver, deps) => - deps ++ ( - CrossVersion.partialVersion(ver) match { - case Some((2, scalaMajor)) if scalaMajor == 11 => - Seq( - "org.typelevel" %% "cats-free" % "0.8.0" - , "org.scalatest" % "scalatest_2.11" % "3.0.0" % "test" - , compilerPlugin("com.milessabin" % "si2712fix-plugin" % "1.2.0" cross CrossVersion.full) - ) - case Some((2, scalaMajor)) if scalaMajor == 12 => - Seq( - "org.typelevel" % "cats-free_2.12.0-RC2" % "0.8.0" - , "org.scalatest" % "scalatest_2.12" % "3.0.0" % "test" - ) - } - ) - } + libraryDependencies ++= Seq( + "org.typelevel" %% "cats-free" % "0.8.1" + , "org.scalatest" %% "scalatest" % "3.0.0" % Test + ) ++ (CrossVersion.partialVersion(scalaVersion.value) match { + case Some((2, scalaMajor)) if scalaMajor == 11 => + compilerPlugin("com.milessabin" % "si2712fix-plugin" % "1.2.0" cross CrossVersion.full) :: Nil + case _ => Nil + }) ) diff --git a/project/build.properties b/project/build.properties index a6e117b..27e88aa 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=0.13.8 +sbt.version=0.13.13 From 66271f40f1a2acd66956731650c201509dd061c3 Mon Sep 17 00:00:00 2001 From: Dustin Whitney Date: Thu, 15 Dec 2016 11:58:52 -0500 Subject: [PATCH 15/19] updated to cats 0.8.1 and added scala 2.12.1 --- build.sbt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.sbt b/build.sbt index aa4a8e8..b25d373 100644 --- a/build.sbt +++ b/build.sbt @@ -1,12 +1,12 @@ lazy val commonSettings = Seq( organization := "com.projectseptember" - , version := "0.6.5" + , version := "0.6.6" , resolvers ++= Seq( Resolver.mavenLocal , Resolver.sonatypeRepo("releases") , Resolver.sonatypeRepo("snapshots")) , scalaVersion := "2.11.8" - , crossScalaVersions := Seq("2.11.8", "2.12.0") + , crossScalaVersions := Seq("2.11.8", "2.12.0", "2.12.1") , bintrayOrganization := Some("projectseptemberinc") , licenses += ("Apache-2.0", url("http://www.apache.org/licenses/LICENSE-2.0")) , addCompilerPlugin("org.spire-math" % "kind-projector" % "0.9.3" cross CrossVersion.binary) From e40f5aaa6ad51ba6e64006f3b99404d0c7b70355 Mon Sep 17 00:00:00 2001 From: mandubian Date: Thu, 15 Dec 2016 18:06:08 +0100 Subject: [PATCH 16/19] broken test with latest cats --- src/test/scala/AppSpec.scala | 4 ++-- src/test/scala/FreekitSpec.scala | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/test/scala/AppSpec.scala b/src/test/scala/AppSpec.scala index af22053..ec08521 100644 --- a/src/test/scala/AppSpec.scala +++ b/src/test/scala/AppSpec.scala @@ -586,8 +586,7 @@ class AppSpec extends FlatSpec with Matchers { val interpreters = foo2Future :&: logger2Future :&: bar2Future :&: kvs2Future - Await.result(prg.value.interpret(interpreters), 10.seconds) - + Await.result(prg.value.interpret(interpreters), 10.seconds) } "freek" should "manage monadic onions of result types wrap/peelRight" in { @@ -1119,6 +1118,7 @@ class AppSpec extends FlatSpec with Matchers { val r = Await.result(free.interpret(foo1Future :&: foo3Future :&: foo4Future), 2.seconds) println("r:"+r) + () } // "freek" should "special case" in { diff --git a/src/test/scala/FreekitSpec.scala b/src/test/scala/FreekitSpec.scala index bf265c8..f6c37bc 100644 --- a/src/test/scala/FreekitSpec.scala +++ b/src/test/scala/FreekitSpec.scala @@ -188,5 +188,24 @@ class FreekitSpec extends FlatSpec with Matchers { } } + "Freek" should "work" in { + import cats._ + import cats.free.Free + import cats.implicits._ + + import freek._ + + object Test { + sealed trait Instruction[T] + // Seq[Int] doesn't represent and error but is the return type of Get + final case class Get() extends Instruction[List[Int]] + + type PRG = Instruction :|: NilDSL + val PRG = freek.DSL.Make[PRG] + type O = Option :&: List :&: Bulb + + Get().freek[PRG].onionT[O] + } + } } \ No newline at end of file From e0f02fff1b3844dd84fb985b16b081db25a0cf6b Mon Sep 17 00:00:00 2001 From: ruben Date: Fri, 13 Jan 2017 20:25:17 +0100 Subject: [PATCH 17/19] change README to mention expand function under 'Combine Programs' --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7ee2ca6..2bb9a21 100644 --- a/README.md +++ b/README.md @@ -332,7 +332,7 @@ To prepend one or more DSL to an existing combination of DSL into a new program, for { _ <- Log.debug(s"Searching for value id: $id").freek[PRG] name <- KVS.Get(id).freek[PRG] - e <- DB.findById(id).freek[PRG] + e <- DB.findById(id).expand[PRG] file <- File.Get(e.file).freek[PRG] _ <- Log.debug(s"Found file:$file").freek[PRG] } yield (file) @@ -343,7 +343,7 @@ Please note: - there is no `NilDSL` at the end because it's brought by `DBService.PRG` - `:|:` also appends a list of DSL at the end - +- the use of the `expand` function instead of `freek` for the findById operation, the `expand` function allows the use of a program defined with a smaller DSL in one with a bigger DSL
From 00674bb6727e9037453d51188ef889a5906a7be4 Mon Sep 17 00:00:00 2001 From: Damir Vandic Date: Fri, 27 Jan 2017 10:42:21 +0100 Subject: [PATCH 18/19] bumping 0.6.7: cats 0.9.0 --- build.sbt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.sbt b/build.sbt index b25d373..b8681e1 100644 --- a/build.sbt +++ b/build.sbt @@ -1,6 +1,6 @@ lazy val commonSettings = Seq( organization := "com.projectseptember" - , version := "0.6.6" + , version := "0.6.7" , resolvers ++= Seq( Resolver.mavenLocal , Resolver.sonatypeRepo("releases") @@ -30,7 +30,7 @@ lazy val root = (project in file(".")) ) .settings( libraryDependencies ++= Seq( - "org.typelevel" %% "cats-free" % "0.8.1" + "org.typelevel" %% "cats-free" % "0.9.0" , "org.scalatest" %% "scalatest" % "3.0.0" % Test ) ++ (CrossVersion.partialVersion(scalaVersion.value) match { case Some((2, scalaMajor)) if scalaMajor == 11 => From 8aa0e47dc48c8c92b4b7e497c2806a401095ff70 Mon Sep 17 00:00:00 2001 From: elongeau Date: Sun, 29 Jan 2017 21:34:25 +0100 Subject: [PATCH 19/19] Add highlighting to scala code some block have no syntax hightlighting --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2bb9a21..64d98bf 100644 --- a/README.md +++ b/README.md @@ -688,7 +688,7 @@ Instead of `Foo2(i).freek[PRG].onionT[O].peelRight3`, you can write `Foo2(i).fre
#### Bored adding `.free[PRG]` on each line? Use `Freekit` trick -``` +```scala type PRG = Foo1 :|: Foo2 :|: Log :|: NilDSL val PRG = DSL.Make[PRG] @@ -716,7 +716,7 @@ This works in basic cases & naturally as soon as you have embedded `for-comprehe
#### Bored adding `.free[PRG].onionT[O]` on each line? Use `Freekito` trick -``` +```scala type PRG = Foo1 :|: Foo2 :|: Log :|: NilDSL val PRG = DSL.Make[PRG]