Created
May 30, 2020 20:38
-
-
Save johnynek/700c69b6fd702cefa6c8df4f6f096adb to your computer and use it in GitHub Desktop.
Here is an interesting pattern where you want to call an allocation function of a given size once for an entire graph, but you want to individually use alloc as you are building up the graph.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import cats._ | |
import cats.implicits._ | |
final case class Allocator[F[_], -T, A] private (slotCount: Int, builder: List[T] => F[A]) { | |
def map[B](fn: A => B)(implicit F: Functor[F]): Allocator[F, T, B] = | |
Allocator(slotCount, builder.andThen(_.map(fn))) | |
def pipeTo[T1 <: T, B](that: Allocator[F, T1, A => B])(implicit F: Applicative[F]): Allocator[F, T1, B] = | |
Allocator(slotCount + that.slotCount, | |
{ (slots) => | |
val thisSlots = slots.take(slotCount) | |
val thatSlots = slots.drop(slotCount) | |
(builder(thisSlots), that.builder(thatSlots)).mapN { (a, fn) => fn(a) } | |
}) | |
def product[T1 <: T, B](that: Allocator[F, T1, B])(implicit F: Applicative[F]): Allocator[F, T1, (A, B)] = | |
pipeTo(that.map { b => { a => (a, b) } }) | |
def run[T1 <: T](fn: Int => F[List[T1]])(implicit F: Monad[F]): F[A] = | |
fn(slotCount).flatMap(builder) | |
} | |
object Allocator { | |
def liftF[F[_], A](a: F[A]): Allocator[F, Any, A] = | |
Allocator(0, { _: List[Any] => a }) | |
def pure[F[_], A](a: A)(implicit F: Applicative[F]): Allocator[F, Any, A] = liftF(F.pure(a)) | |
def allocSlot[F[_], A](implicit me: MonadError[F, Throwable]): Allocator[F, A, A] = | |
Allocator(1, { slots => | |
me.catchNonFatal(slots.head) | |
}) | |
implicit def applicativeAllocator[F[_]: Applicative, T]: Applicative[Allocator[F, T, *]] = | |
new Applicative[Allocator[F, T, *]] { | |
def pure[A](a: A): Allocator[F, T, A] = Allocator.pure(a) | |
def ap[A, B](ff: Allocator[F, T, A => B])(fa: Allocator[F, T, A]): Allocator[F, T, B] = | |
fa.pipeTo(ff) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment