-
-
Save EECOLOR/c9037d1c56c3c4b59c75 to your computer and use it in GitHub Desktop.
This file contains 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
package p { | |
object Test { | |
import construction.Monadic | |
import execution.Bimonad | |
def main(args: Array[String]): Unit = { | |
val expression = Monadic[List](10) flatMap (1 to _ toList) coflatMap (_.sum) | |
val result = expression runWith ListBimonad | |
println(result + " <- " + expression) | |
// output: 55 <- CoflatMap(FlatMap(Pure(10),<function1>),<function1>) | |
} | |
private object ListBimonad extends Bimonad.Of[List] { | |
def fmap[A, B] = _ map _ | |
def join[A] = _.flatten | |
def pure[A] = List(_) | |
def cojoin[A] = List(_) | |
def copure[A] = _.head | |
} | |
} | |
package execution { | |
trait `Some name in the domain` { type F[_] } | |
trait Functor extends `Some name in the domain` { def fmap[A, B]: (F[A], (A => B)) => F[B] } | |
trait Copointed extends Functor { def copure[A]: F[A] => A } | |
trait Comonad extends Copointed { def cojoin[A]: F[A] => F[F[A]] } | |
trait Pointed extends Functor { def pure[A]: A => F[A] } | |
trait Monad extends Pointed { def join[A]: F[F[A]] => F[A] } | |
trait Bimonad extends Monad with Comonad | |
object Bimonad { | |
type Of[G[_]] = `It should not be necessary to add this trait`[G] | |
trait `It should not be necessary to add this trait`[G[_]] extends Bimonad { | |
type F[x] = G[x] | |
} | |
} | |
} | |
package construction { | |
import execution.Bimonad | |
sealed trait Monadic[F[_], A] extends Monadic.Operations[F, A] | |
object Monadic { | |
def apply[F[_], A](fa: F[A]): Monadic[F, A] = Copure(fa) | |
def apply[F[_]]: Factory[F] = new Factory[F] | |
class Factory[F[_]] { | |
def apply[A](a: A): Monadic[F, A] = Pure[F, A](a) | |
} | |
private case class Pure[F[_], A](x: A) extends Monadic[F, A] | |
private case class Copure[F[_], A](x: F[A]) extends Monadic[F, A] | |
private case class Map[F[_], A, B](prev: Monadic[F, A], f: A => B) extends Monadic[F, B] | |
private case class FlatMap[F[_], A, B](prev: Monadic[F, A], f: A => F[B]) extends Monadic[F, B] | |
private case class CoflatMap[F[_], A, B](prev: Monadic[F, A], f: F[A] => B) extends Monadic[F, B] | |
trait Operations[F[_], A] { _: Monadic[F, A] => | |
private type Result[B] = Monadic[F, B] | |
def map[B](f: A => B): Result[B] = Map(this, f) | |
def flatMap[B](f: A => F[B]): Result[B] = FlatMap(this, f) | |
def coflatMap[B](f: F[A] => B): Result[B] = CoflatMap(this, f) | |
def runWith(implicit F: Bimonad.Of[F]): A = executed |> F.copure | |
private[Operations] def executed(implicit F: Bimonad.Of[F]): F[A] = { | |
def fmap[A, B]: (A => B) => F[A] => F[B] = f => fa => F.fmap(fa, f) | |
this match { | |
case Pure(x) => x |> F.pure | |
case Copure(x) => x | |
case Map(prev, f) => prev.executed |> fmap(f) | |
case FlatMap(prev, f) => prev.executed |> fmap(f) |> F.join | |
case CoflatMap(prev, f) => prev.executed |> F.cojoin |> fmap(f) | |
} | |
} | |
private implicit class ForwardPipe[A](x: A) { def |>[B](f: A => B): B = f(x) } | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I am convinced by your arguments and it's quite funny that you mention "I don't want to give it a name at all, but I am often forced to", I totally agree.
Another reason was that by placing them in a trait helps readers of the source code could see that there are methods available. I however tend to lean to your side on this one.