Skip to content

Commit

Permalink
factor ParallelViaProduct to possibly use elsewhere
Browse files Browse the repository at this point in the history
  • Loading branch information
johnynek committed Sep 17, 2023
1 parent 2f3f5e2 commit ccab783
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 35 deletions.
55 changes: 20 additions & 35 deletions core/src/main/scala/org/bykn/bosatsu/DefRecursionCheck.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import org.typelevel.paiges.Doc
import cats.implicits._

import Identifier.Bindable
import cats.Applicative

/**
* Recursion in bosatsu is only allowed on a substructural match
Expand Down Expand Up @@ -268,44 +267,30 @@ object DefRecursionCheck {
implicit val parallelSt: cats.Parallel[St] = {
val m = cats.Monad[St]

new cats.Parallel[St] {
type F[A] = St[A]
def parallel = new cats.arrow.FunctionK[St, F] {
def apply[A](st: St[A]) = st
}
def sequential = new cats.arrow.FunctionK[F, St] {
def apply[A](st: St[A]) = st
}
new ParallelViaProduct[St] {
def monad = m
def applicative: Applicative[F] =
new Applicative[F] {
def pure[A](a: A) = m.pure(a)
def ap[A, B](ff: F[A => B])(fa: F[A]): F[B] =
map(product(ff, fa)) { case (fn, a) => fn(a) }

override def product[A, B](fa: F[A], fb: F[B]): F[(A, B)] = {
type E[+X] = Either[NonEmptyList[RecursionError], X]
val fna: E[State => E[(State, A)]] = fa.runF
val fnb: E[State => E[(State, B)]] = fb.runF

new cats.data.IndexedStateT((fna, fnb).parMapN { (fn1, fn2) =>
{ (state: State) =>
fn1(state) match {
case Right((s2, a)) => fn2(s2).map { case (st, b) => (st, (a, b)) }
case Left(nel1) =>
// just skip and merge
fn2(state) match {
case Right(_) => Left(nel1)
case Left(nel2) => Left(nel1 ::: nel2)
}
def parallelProduct[A, B](fa: St[A], fb: St[B]) = {
type E[+X] = Either[NonEmptyList[RecursionError], X]
val fna: E[State => E[(State, A)]] = fa.runF
val fnb: E[State => E[(State, B)]] = fb.runF

new cats.data.IndexedStateT((fna, fnb).parMapN { (fn1, fn2) =>
{ (state: State) =>
fn1(state) match {
case Right((s2, a)) => fn2(s2).map { case (st, b) => (st, (a, b)) }
case Left(nel1) =>
// just skip and merge
fn2(state) match {
case Right(_) => Left(nel1)
case Left(nel2) => Left(nel1 ::: nel2)
}
}
})
}
override def map[A, B](fa: F[A])(fn: A => B) = m.map(fa)(fn)
}
}
}
})
}
}
}

// Scala has trouble infering types like St, we we make these typed
// helper functions to use below
def failSt[A](err: RecursionError): St[A] =
Expand Down
31 changes: 31 additions & 0 deletions core/src/main/scala/org/bykn/bosatsu/ParallelViaProduct.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package org.bykn.bosatsu

import cats.arrow.FunctionK
import cats.{Parallel, Applicative}

// Implement Parallel by implementing just Product
abstract class ParallelViaProduct[G[_]] extends Parallel[G] { self =>

type F[A] = G[A]
val parallel = new FunctionK[G, F] {
def apply[A](ga: G[A]) = ga
}

val sequential = new FunctionK[F, G] {
def apply[A](fa: F[A]) = fa
}

def parallelProduct[A, B](fa: F[A], fb: F[B]): F[(A, B)]

val applicative: Applicative[F] =
new Applicative[F] { self =>
def pure[A](a: A) = monad.pure(a)

final def ap[A, B](ff: F[A => B])(fa: F[A]): F[B] =
monad.map(parallelProduct(ff, fa)) { case (fn, a) => fn(a) }

override def map[A, B](fa: F[A])(fn: A => B) = monad.map(fa)(fn)

override def product[A, B](fa: F[A], fb: F[B]) = parallelProduct(fa, fb)
}
}

0 comments on commit ccab783

Please sign in to comment.