1717package hxl
1818
1919import cats ._
20+ import cats .arrow ._
2021import cats .implicits ._
2122
2223/*
2324 * Hxl is a value that that represents a computation that may be batched.
2425 * Hxl forms an applicative, and only an applicative.
25- * `andThen` exists as an alternative to `flatMap` (since that wouldn't be lawful) , much like `Validated`.
26+ * `andThen` exists as an alternative to `flatMap`, much like `Validated`.
2627 */
2728sealed trait Hxl [F [_], A ] {
2829 def andThen [B ](f : A => Hxl [F , B ])(implicit F : Functor [F ]): Hxl [F , B ]
@@ -88,6 +89,8 @@ object Hxl {
8889 runPar(node)
8990 }
9091
92+ def unit [F [_]]: Hxl [F , Unit ] = Done (())
93+
9194 def embedF [F [_], A ](fa : F [Hxl [F , A ]]): Hxl [F , A ] = LiftF (fa)
9295
9396 def liftF [F [_]: Functor , A ](fa : F [A ]): Hxl [F , A ] = embedF(fa.map(Done (_)))
@@ -101,38 +104,19 @@ object Hxl {
101104 apply[F , K , V ](k, source)
102105 .flatMapF(F .fromOption(_, new RuntimeException (show " Key $k not found " )))
103106
104- implicit def parallelForHxl [F [_]](implicit P : Parallel [F ]): Parallel [Hxl [F , * ]] = {
105- type G [A ] = Hxl [F , A ]
106- new Parallel [G ] {
107- type F [A ] = Hxl [P .F , A ]
108-
109- override def sequential : F ~> G = new (F ~> G ) {
110- def apply [A ](fa : F [A ]): G [A ] = fa.mapK(P .sequential)(P .monad)
111- }
112- override def parallel : G ~> F = new (G ~> F ) {
113- def apply [A ](fa : G [A ]): F [A ] = fa.mapK(P .parallel)(P .applicative)
114- }
115-
116- override def applicative : Applicative [F ] = applicativeForHxl[P .F ](P .applicative)
117-
118- override def monad : Monad [G ] = {
119- implicit val m = P .monad
120- new Monad [G ] {
121- override def flatMap [A , B ](fa : G [A ])(f : A => G [B ]): G [B ] = fa.monadic.flatMap(f(_).monadic).hxl
122- override def tailRecM [A , B ](a : A )(f : A => G [Either [A , B ]]): G [B ] = a.tailRecM(f(_).monadic).hxl
123- override def pure [A ](x : A ): G [A ] = Done (x)
124- }
125- }
126- }
127- }
128-
129- implicit def applicativeForHxl [F [_]: Applicative ]: Applicative [Hxl [F , * ]] = {
130- type G [A ] = Hxl [F , A ]
131- new Applicative [G ] {
132- def pure [A ](x : A ): G [A ] = Done (x)
133- def ap [A , B ](ff : G [A => B ])(fa : G [A ]): G [B ] =
107+ // Almost the same signature as parallel, except we don't have a monad, but a functor instead
108+ // This is because of the free monad structure of Hxl, we can defer Monad evidence until we need to run
109+ def applicativeInstance [F [_]: Functor , G [_]: Applicative ](
110+ fg : F ~> G ,
111+ gf : G ~> F
112+ ): Applicative [Hxl [F , * ]] = {
113+ implicit def self : Applicative [Hxl [F , * ]] = applicativeInstance[F , G ](fg, gf)
114+ type H [A ] = Hxl [F , A ]
115+ new Applicative [H ] {
116+ def pure [A ](x : A ): H [A ] = Done (x)
117+ def ap [A , B ](ff : H [A => B ])(fa : H [A ]): H [B ] =
134118 (ff, fa) match {
135- case (LiftF (fa), LiftF (fb)) => LiftF ((fa, fb).mapN(_ <*> _))
119+ case (LiftF (fa), LiftF (fb)) => LiftF (gf((fg(fa), fg( fb)) .mapN(_ <*> _) ))
136120 case (LiftF (fa), h) => LiftF (fa.map(_ <*> h))
137121 case (h, LiftF (fa)) => LiftF (fa.map(h <*> _))
138122 case (Done (f), Done (a)) => Done (f(a))
@@ -144,20 +128,46 @@ object Hxl {
144128 }
145129 }
146130 }
131+
132+ implicit def applicativeForHxl [F [_]: Applicative ]: Applicative [Hxl [F , * ]] =
133+ applicativeInstance[F , F ](FunctionK .id[F ], FunctionK .id[F ])
147134}
148135
149136/*
150137 * A monadic view of Hxl.
151138 * The equivalent counterpart for `Hxl` as `Either` is to `Validated`.
152- * Is effectively the identity monad transformer.
153139 */
154140final case class HxlM [F [_], A ](hxl : Hxl [F , A ]) {
155141 def mapK [G [_]: Functor ](fk : F ~> G ): HxlM [G , A ] = HxlM (hxl.mapK(fk))
156142
157143 def flatMapF [B ](f : A => F [B ])(implicit F : Functor [F ]): HxlM [F , B ] = HxlM (hxl.flatMapF(f))
144+
145+ def foldMap [G [_]](fk : Hxl .Compiler [F , G ])(implicit G : Monad [G ]): G [A ] = hxl.foldMap(fk)
146+
147+ def applicative : Hxl [F , A ] = hxl
158148}
159149
160150object HxlM {
151+ def unit [F [_]]: HxlM [F , Unit ] = HxlM (Hxl .unit[F ])
152+
153+ def liftF [F [_]: Functor , A ](fa : F [A ]): HxlM [F , A ] = HxlM (Hxl .liftF(fa))
154+
155+ def pure [F [_], A ](a : A ): HxlM [F , A ] = HxlM (Hxl .pure(a))
156+
157+ def apply [F [_], K , V ](k : K , source : DataSource [F , K , V ]): HxlM [F , Option [V ]] =
158+ HxlM (Hxl (k, source))
159+
160+ def force [F [_]: ApplicativeThrow , K : Show , V ](k : K , source : DataSource [F , K , V ]): HxlM [F , V ] =
161+ HxlM (Hxl .force(k, source))
162+
163+ def monadicK [F [_]]: Hxl [F , * ] ~> HxlM [F , * ] = new (Hxl [F , * ] ~> HxlM [F , * ]) {
164+ def apply [A ](fa : Hxl [F , A ]): HxlM [F , A ] = fa.monadic
165+ }
166+
167+ def applicativeK [F [_]]: HxlM [F , * ] ~> Hxl [F , * ] = new (HxlM [F , * ] ~> Hxl [F , * ]) {
168+ def apply [A ](fa : HxlM [F , A ]): Hxl [F , A ] = fa.applicative
169+ }
170+
161171 // Monad for HxlM
162172 // HxlM can implement any covariant typeclass (but not contravariant ones since `F ~> HxlM` but not `HxlM ~> F`).
163173 implicit def monadForHxlM [F [_]: Monad ]: Monad [HxlM [F , * ]] = {
@@ -174,9 +184,41 @@ object HxlM {
174184 }
175185 }
176186 }
187+ }
188+
189+ object instances {
190+
191+ /** A parallel instance for Hxl a bit of a footgun since (P: Parallel[F, Hxl]).monad: Monad[Hxl[F, *]], which can have very unfortunate
192+ * consequences if you're not careful.
193+ *
194+ * import hxl.instances.parallel._
195+ */
196+ object parallel {
197+ implicit def parallelForHxl [F [_]](implicit P : Parallel [F ]): Parallel [Hxl [F , * ]] = {
198+ implicit def m : Monad [F ] = P .monad
199+ implicit def a : Applicative [P .F ] = P .applicative
200+ type F0 [A ] = F [A ]
201+ new Parallel [Hxl [F , * ]] {
202+ type F [A ] = Hxl [F0 , A ]
203+ override def sequential : F ~> F = FunctionK .id[F ]
204+ override def parallel : F ~> F = FunctionK .id[F ]
205+ override def applicative : Applicative [F ] = Hxl .applicativeInstance[F0 , P .F ](P .parallel, P .sequential)
206+ override def monad : Monad [Hxl [F0 , * ]] = {
207+ implicit val m = P .monad
208+ new Monad [Hxl [F0 , * ]] {
209+ override def flatMap [A , B ](fa : Hxl [F0 , A ])(f : A => Hxl [F0 , B ]): Hxl [F0 , B ] =
210+ fa.andThen(f)
211+ override def tailRecM [A , B ](a : A )(f : A => Hxl [F0 , Either [A , B ]]): Hxl [F0 , B ] =
212+ a.tailRecM(f(_).monadic).hxl
213+ override def pure [A ](x : A ): Hxl [F0 , A ] = Hxl .Done (x)
214+ }
215+ }
216+ }
217+ }
218+ }
177219
178220 /*
179- * A parallel instance for HxlM is dangerously ambiguous.
221+ * A parallel instance for HxlM is ambiguous.
180222 * Consider the difference between parallel composition of the Batch axis and the lifted effect axis
181223 * Which one of the following do you want:
182224 * Hxl[F, A] | F[A]
@@ -187,15 +229,29 @@ object HxlM {
187229 *
188230 * With Hxl (applicative) then the Hxl axis is Batch, and ap / parAp controls the effect axis
189231 * With HxlM (monad) then the Hxl axis is Seq and the effect axis is ambigious
190- * If you need a parallel instance for Hxl consider implementing one ad-hoc, here is an example:
191- * ```scala
192- * implicit def parallelForHxlM[G[_]: Monad]: Parallel[HxlM[G, *]] = new Parallel[HxlM[G, *]] {
193- * type F[A] = Hxl[G, A]
194- * override def sequential: F ~> HxlM[G, *] = FunctionK.liftFunction(HxlM(_))
195- * override def parallel: HxlM[G, *] ~> F = FunctionK.liftFunction(_.hxl)
196- * override def applicative: Applicative[F] = Hxl.applicativeForHxl[G]
197- * override def monad: Monad[HxlM[G, *]] = monadForHxlM[G]
198- * }
199- * ```
232+ * Pick one by importing the appropriate instance:
233+ * import hxl.instances.hxlm.parallel._
234+ * // or
235+ * import hxl.instances.hxlm.sequential._
200236 */
237+ object hxlm {
238+ object parallel {
239+ implicit def parallelHxlMForParallelEffect [G [_]](implicit P : Parallel [G ]): Parallel [HxlM [G , * ]] = {
240+ implicit def applicativePF : Applicative [P .F ] = P .applicative
241+ implicit def monadF : Monad [G ] = P .monad
242+ new Parallel [HxlM [G , * ]] {
243+ type F [A ] = Hxl [G , A ]
244+ override def sequential : F ~> HxlM [G , * ] = HxlM .monadicK[G ]
245+ override def parallel : HxlM [G , * ] ~> F = HxlM .applicativeK[G ]
246+ override def applicative : Applicative [F ] = Hxl .applicativeInstance[G , P .F ](P .parallel, P .sequential)
247+ override def monad : Monad [HxlM [G , * ]] = HxlM .monadForHxlM[G ]
248+ }
249+ }
250+ }
251+
252+ object sequential {
253+ implicit def parallelHxlMForParallelEffect [G [_]: Monad ]: Parallel [HxlM [G , * ]] =
254+ parallel.parallelHxlMForParallelEffect[G ](Parallel .identity[G ])
255+ }
256+ }
201257}
0 commit comments