@@ -26,7 +26,8 @@ import cats.implicits._
2626 * `andThen` exists as an alternative to `flatMap`, much like `Validated`.
2727 */
2828sealed trait Hxl [F [_], A ] {
29- def andThen [B ](f : A => Hxl [F , B ])(implicit F : Functor [F ]): Hxl [F , B ]
29+ def andThen [B ](f : A => Hxl [F , B ]): Hxl [F , B ] =
30+ Hxl .AndThen (this , f)
3031
3132 def flatMapF [B ](f : A => F [B ])(implicit F : Functor [F ]): Hxl [F , B ] =
3233 andThen(a => Hxl .liftF(f(a)))
@@ -49,9 +50,9 @@ sealed trait Hxl[F[_], A] {
4950 def optimized (implicit F : Monad [F ]): Either [Hxl [F , A ], F [Hxl [F , A ]]]
5051
5152 // Aligns this hxl, this is a hint for future composition that
52- def align : Hxl [F , A ] = Hxl .align(this )
53+ // def align: Hxl[F, A] = Hxl.align(this)
5354
54- def alignM : HxlM [F , A ] = align.monadic
55+ // def alignM: HxlM[F, A] = align.monadic
5556}
5657
5758object Hxl {
@@ -61,50 +62,46 @@ object Hxl {
6162
6263 // Almost a free monad
6364 final case class Done [F [_], A ](value : A ) extends Hxl [F , A ] {
64- def andThen [B ](f : A => Hxl [F , B ])(implicit F : Functor [F ]): Hxl [F , B ] = f(value)
6565 def mapK [G [_]: Functor ](fk : F ~> G ): Hxl [G , A ] = Done (value)
6666 def optimized (implicit F : Monad [F ]) = Left (this )
6767 }
68- final case class Bind [F [_], A , B ](
69- requests : Requests [F , A ],
70- f : A => Hxl [F , B ]
71- ) extends Hxl [F , B ] {
72- def andThen [C ](f2 : B => Hxl [F , C ])(implicit F : Functor [F ]): Hxl [F , C ] =
73- Bind (requests, f.andThen(_.andThen(f2)))
74- def mapK [G [_]: Functor ](fk : F ~> G ): Hxl [G , B ] =
75- Bind (requests.mapK(fk), f.andThen(_.mapK(fk)))
76- def optimized (implicit F : Monad [F ]) = Left (Bind (requests.optimized, f))
68+ final case class Run [F [_], A ](requests : Requests [F , A ]) extends Hxl [F , A ] {
69+ def mapK [G [_]: Functor ](fk : F ~> G ): Hxl [G , A ] = Run (requests.mapK(fk))
70+ def optimized (implicit F : Monad [F ]) = Left (Run (requests.optimized))
7771 }
7872 final case class LiftF [F [_], A ](unFetch : F [Hxl [F , A ]]) extends Hxl [F , A ] {
79- def andThen [B ](f : A => Hxl [F , B ])(implicit F : Functor [F ]): Hxl [F , B ] =
80- LiftF (unFetch.map(_.andThen(f)))
8173 def mapK [G [_]: Functor ](fk : F ~> G ): Hxl [G , A ] =
8274 LiftF (fk(unFetch).map(_.mapK(fk)))
8375 def optimized (implicit F : Monad [F ]) =
8476 unFetch.flatMap(_.optimized.leftMap(F .pure(_)).merge).asRight
8577 }
86- final case class Align [F [_], A ](fa : Hxl [F , A ]) extends Hxl [F , A ] {
87- def andThen [B ](f : A => Hxl [F , B ])(implicit F : Functor [F ]): Hxl [F , B ] =
88- Align (fa.andThen(f))
89- def mapK [G [_]: Functor ](fk : F ~> G ): Hxl [G , A ] =
90- Align (fa.mapK(fk))
91- def optimized (implicit F : Monad [F ]) =
92- Left (this )
93-
78+ // final case class Align[F[_], A](fa: Hxl[F, A]) extends Hxl[F, A] {
79+ // def mapK[G[_]: Functor](fk: F ~> G): Hxl[G, A] =
80+ // Align(fa.mapK(fk))
81+ // def optimized(implicit F: Monad[F]) =
82+ // Left(this)
83+ // }
84+ final case class AndThen [F [_], A , B ](fa : Hxl [F , A ], fb : A => Hxl [F , B ]) extends Hxl [F , B ] {
85+ override def mapK [G [_]: Functor ](fk : F ~> G ): Hxl [G , B ] = ???
86+
87+ override def optimized (implicit F : Monad [F ]): Either [Hxl [F , B ], F [Hxl [F , B ]]] = ???
9488 }
9589
9690 def parallelRunner [F [_]](implicit F : Parallel [F ]): Compiler [F , F ] = new Compiler [F , F ] {
9791 implicit val M : Monad [F ] = F .monad
9892 override def apply [A ](fa : Hxl [F , A ]): F [Either [Hxl [F , A ], A ]] =
99- fa match {
100- case Done (a) => M .pure(Right (a))
101- case Align (fa) => M .pure(Left (fa))
102- case LiftF (unFetch) => unFetch.map(Left (_))
103- case bind : Bind [F , a, b] =>
104- Requests
105- .run[F , a](bind.requests)
106- .map(bind.f)
107- .map(_.asLeft)
93+ M .unit >> {
94+ fa match {
95+ case Done (a) => M .pure(Right (a))
96+ // case Align(fa) => M.pure(Left(fa))
97+ case LiftF (unFetch) => unFetch.map(Left (_))
98+ case at : AndThen [F , a, A ] =>
99+ apply(at.fa).map {
100+ case Left (h) => Left (h.andThen(at.fb))
101+ case Right (a) => Left (at.fb(a))
102+ }
103+ case bind : Run [F , A ] => Requests .run[F , A ](bind.requests).map(Right (_))
104+ }
108105 }
109106 }
110107
@@ -126,18 +123,18 @@ object Hxl {
126123
127124 def apply [F [_], K , V ](k : K , source : DataSource [F , K , V ]): Hxl [F , Option [V ]] =
128125 source.optimization match {
129- case Some (ev) => Bind [F , Unit , Option [V ]](Requests .discard (source, k), x => Done ( Some (ev(x ))))
130- case None => Bind [F , Option [V ], Option [ V ]] (Requests .lift(source, k), Done (_ ))
126+ case Some (ev) => Run [F , Option [V ]](Requests .empty (source, k, Some (ev(() ))))
127+ case None => Run [F , Option [V ]] (Requests .lift(source, k))
131128 }
132129
133130 def discard [F [_], K , V ](k : K , source : DataSource [F , K , V ]): Hxl [F , Unit ] =
134- Bind [F , Unit , Unit ](Requests .discard(source, k), Done (_ ))
131+ Run [F , Unit ](Requests .discard(source, k))
135132
136133 def force [F [_], K : Show , V ](k : K , source : DataSource [F , K , V ])(implicit F : ApplicativeThrow [F ]): Hxl [F , V ] =
137134 apply[F , K , V ](k, source)
138135 .flatMapF(F .fromOption(_, new RuntimeException (show " Key $k not found " )))
139136
140- def align [F [_], A ](fa : Hxl [F , A ]): Hxl [F , A ] = Align (fa)
137+ // def align[F[_], A](fa: Hxl[F, A]): Hxl[F, A] = Align(fa)
141138
142139 // Almost the same signature as parallel, except we don't have a monad, but a functor instead
143140 // This is because of the free monad structure of Hxl, we can defer Monad evidence until we need to run
@@ -149,27 +146,37 @@ object Hxl {
149146 type H [A ] = Hxl [F , A ]
150147 new Applicative [H ] {
151148 def pure [A ](x : A ): H [A ] = Done (x)
152- def ap [A , B ](ff : H [A => B ])(fa : H [A ]): H [B ] =
149+ def ap [A , B ](ff : H [A => B ])(fa : H [A ]): H [B ] = {
153150 (ff, fa) match {
154151 case (LiftF (fa), LiftF (fb)) => LiftF (gf((fg(fa), fg(fb)).mapN(_ <*> _)))
155152 case (LiftF (fa), h) => LiftF (fa.map(_ <*> h))
156153 case (h, LiftF (fa)) => LiftF (fa.map(h <*> _))
157-
158- case (Align (fa), Align (fb)) => Align (fa.ap(fb))
159- // Synthetically align
160- case (Align (fa), Done (fb)) => Align (fa.map(_(fb)))
161- case (Done (fa), Align (fb)) => Align (fb.map(fa(_)))
162- // Missing align on right side, defer fa until later
163- case (Align (fa), b2 : Bind [F , a2, A ]) => Bind [F , a2, B ](b2.requests, a2 => fa.ap(b2.f(a2)))
164- case (b1 : Bind [F , a1, A => B ], Align (fb)) => Bind [F , a1, B ](b1.requests, a1 => b1.f(a1).ap(fb))
154+ case (at : AndThen [F , a1, A => B ], ab : AndThen [F , a2, A ]) =>
155+ AndThen [F , (a1, a2), B ](
156+ self.tuple2(at.fa, ab.fa),
157+ { case (a1, a2) => at.fb(a1).ap(ab.fb(a2)) }
158+ )
159+
160+ // flatMap <*> batch -> move batch into left side of flatMap
161+ // to be optimistic. The choice is arbitrary.
162+ case (at : AndThen [F , a, A => B ], fb) =>
163+ AndThen [F , (a, A ), B ](
164+ (at.fa, fb).tupled,
165+ { case (a, a2) => self.ap(at.fb(a))(Done (a2)) }
166+ )
167+ case (fa, ab : AndThen [F , a, A ]) =>
168+ AndThen [F , (A => B , a), B ](
169+ (fa, ab.fa).tupled,
170+ { case (f, a2) => self.ap(Done (f))(ab.fb(a2)) }
171+ )
165172
166173 case (Done (f), Done (a)) => Done (f(a))
167- case (b1 : Bind [F , a1, A => B ], b2 : Bind [F , a2, A ]) =>
168- val comb = (b1.requests, b2.requests).tupled
169- Bind [F , (a1, a2), B ](comb, { case (a1, a2) => b1.f(a1) <*> b2.f(a2) })
170- case (b : Bind [F , a, A => B ], Done (a)) => Bind [F , a, B ](b.requests, b.f(_).map(_(a)))
171- case (Done (g), b : Bind [F , a, A ]) => Bind [F , a, B ](b.requests, b.f(_).map(g))
174+ case (r1 : Run [F , A => B ], r2 : Run [F , A ]) =>
175+ self.map(Run ((r1.requests, r2.requests).tupled)) { case (f, a) => f(a) }
176+ case (r : Run [F , A => B ], Done (a)) => Run (r.requests.map(_(a)))
177+ case (Done (f), r : Run [F , A ]) => Run (r.requests.map(f(_)))
172178 }
179+ }
173180 }
174181 }
175182
@@ -214,7 +221,7 @@ object HxlM {
214221
215222 // Monad for HxlM
216223 // HxlM can implement any covariant typeclass (but not contravariant ones since `F ~> HxlM` but not `HxlM ~> F`).
217- implicit def monadForHxlM [F [_]: Functor ]: Monad [HxlM [F , * ]] = {
224+ implicit def monadForHxlM [F [_]]: Monad [HxlM [F , * ]] = {
218225 type G [A ] = HxlM [F , A ]
219226 new Monad [G ] {
220227 override def pure [A ](x : A ): G [A ] = HxlM (Hxl .Done (x))
0 commit comments