|
| 1 | +package iota //#=cats |
| 2 | +package iotaz //#=scalaz |
| 3 | + |
| 4 | +import cats._ //#=cats |
| 5 | +import scalaz._ //#=scalaz |
| 6 | + |
| 7 | +import TListK.:: |
| 8 | + |
| 9 | +package object quasi { |
| 10 | + |
| 11 | + type Quasi[S[_], A] = quasiImpl.Quasi[S, A] |
| 12 | + type Concur[S[_], A] = quasiImpl.Concur[S, A] |
| 13 | + type Subseq[S[_], A] = quasiImpl.Subseq[S, A] |
| 14 | + |
| 15 | + implicit final class QuasiOps[S[_], A](val quasi: Quasi[S, A]) extends AnyVal { |
| 16 | + def concur: Concur[S, A] = quasiImpl.toConcur(quasi) |
| 17 | + def subseq: Subseq[S, A] = quasiImpl.toSubseq(quasi) |
| 18 | + } |
| 19 | + |
| 20 | + final implicit class ConcurOps[S[_], A](val concur: Concur[S, A]) extends AnyVal { |
| 21 | + def quasi: Quasi[S, A] = quasiImpl.fromConcur(concur) |
| 22 | + def subseq: Subseq[S, A] = quasi.subseq |
| 23 | + |
| 24 | + def ap[B](f: Concur[S, A => B]): Concur[S, B] = |
| 25 | + quasiImpl.ap(f.quasi)(concur.quasi).concur |
| 26 | + |
| 27 | + def map[B](f: A => B): Concur[S, B] = ap(Quasi.pure(f).concur) |
| 28 | + } |
| 29 | + |
| 30 | + final implicit class SubseqOps[S[_], A](val subseq: Subseq[S, A]) extends AnyVal { |
| 31 | + def quasi: Quasi[S, A] = quasiImpl.fromSubseq(subseq) |
| 32 | + def concur: Concur[S, A] = quasi.concur |
| 33 | + |
| 34 | + def map[B](f: A => B): Subseq[S, B] = |
| 35 | + flatMap(a => Quasi.pure(f(a)).subseq) |
| 36 | + |
| 37 | + def flatMap[B](f: A => Subseq[S, B]): Subseq[S, B] = |
| 38 | + quasiImpl.flatMap(subseq.quasi)(f.andThen(_.quasi)).subseq |
| 39 | + } |
| 40 | + |
| 41 | + implicit def subseqMonad[S[_]]: Monad[Subseq[S, ?]] = new Monad[Subseq[S, ?]] { |
| 42 | + def pure[A](a: A): Subseq[S, A] = Quasi.pure(a).subseq |
| 43 | + def flatMap[A, B](fa: Subseq[S, A])(f: A => Subseq[S, B]): Subseq[S, B] = |
| 44 | + fa.flatMap(f) |
| 45 | + |
| 46 | + def tailRecM[A, B](a: A)(f: A => Subseq[S, Either[A, B]]): Subseq[S, B] = ??? |
| 47 | + } |
| 48 | + |
| 49 | + implicit def concurApplicative[S[_]]: Applicative[Concur[S, ?]] = new Applicative[Concur[S, ?]] { |
| 50 | + def pure[A](a: A): Concur[S, A] = Quasi.pure(a).concur |
| 51 | + def ap[A, B](ff: Concur[S, A => B])(fa: Concur[S, A]): Concur[S, B] = |
| 52 | + fa.ap(ff) |
| 53 | + } |
| 54 | + |
| 55 | + //#+cats |
| 56 | + implicit def subseqConcurParallel[S[_]]: Parallel[Subseq[S, ?], Concur[S, ?]] = |
| 57 | + new Parallel[Subseq[S, ?], Concur[S, ?]] { |
| 58 | + val parallel: Subseq[S, ?] ~> Concur[S, ?] = |
| 59 | + λ[Subseq[S, ?] ~> Concur[S, ?]](_.quasi.concur) |
| 60 | + val sequential: Concur[S, ?] ~> Subseq[S, ?] = |
| 61 | + λ[Concur[S, ?] ~> Subseq[S, ?]](_.quasi.subseq) |
| 62 | + val applicative: Applicative[Concur[S, ?]] = Applicative[Concur[S, ?]] |
| 63 | + val monad: Monad[Subseq[S, ?]] = Monad[Subseq[S, ?]] |
| 64 | + } |
| 65 | + //#-cats |
| 66 | + |
| 67 | + object Quasi { |
| 68 | + |
| 69 | + def pure[S[_], A](a: A): Quasi[S, A] = quasiImpl.pure(a) |
| 70 | + def liftF[S[_], A](value: S[A]): Quasi[S, A] = quasiImpl.suspend(value) |
| 71 | + |
| 72 | + def toConcur[S[_]]: Quasi[S, ?] ~> Concur[S, ?] = |
| 73 | + λ[Quasi[S, ?] ~> Concur[S, ?]](_.concur) |
| 74 | + |
| 75 | + def toSubseq[S[_]]: Quasi[S, ?] ~> Subseq[S, ?] = |
| 76 | + λ[Quasi[S, ?] ~> Subseq[S, ?]](_.subseq) |
| 77 | + } |
| 78 | + |
| 79 | + private[quasi] sealed trait QuasiImpl { |
| 80 | + type Quasi [S[_], A] |
| 81 | + type Concur[S[_], A] |
| 82 | + type Subseq[S[_], A] |
| 83 | + |
| 84 | + def toConcur[S[_], A](quasi: Quasi[S, A]): Concur[S, A] |
| 85 | + def fromConcur[S[_], A](subseq: Concur[S, A]): Quasi[S, A] |
| 86 | + def toSubseq[S[_], A](quasi: Quasi[S, A]): Subseq[S, A] |
| 87 | + def fromSubseq[S[_], A](subseq: Subseq[S, A]): Quasi[S, A] |
| 88 | + |
| 89 | + def pure[S[_], A](a: A): Quasi[S, A] |
| 90 | + def suspend[S[_], A](value: S[A]): Quasi[S, A] |
| 91 | + def flatMap[S[_], A, B](fa: Quasi[S, A])(f: A => Quasi[S, B]): Quasi[S, B] |
| 92 | + def ap[S[_], A, B](ff: Quasi[S, A => B])(fa: Quasi[S, A]): Quasi[S, B] |
| 93 | + } |
| 94 | + |
| 95 | + private[quasi] val quasiImpl: QuasiImpl = new QuasiImpl { |
| 96 | + type Quasi [S[_], A] = CopK[Effects[S], A] |
| 97 | + type Concur[S[_], A] = CopK[Effects[S], A] |
| 98 | + type Subseq[S[_], A] = CopK[Effects[S], A] |
| 99 | + |
| 100 | + type Effects[S[_]] = |
| 101 | + Pure [S, ?] :: |
| 102 | + Suspend [S, ?] :: |
| 103 | + FlatMap [S, _, ?] :: |
| 104 | + Ap [S, _, ?] :: |
| 105 | + Raise [S, _, ?] :: |
| 106 | + Handle [S, _, ?] :: |
| 107 | + TNilK |
| 108 | + |
| 109 | + type Pure[S[_], A] = A |
| 110 | + type Suspend[S[_], A] = S[A] |
| 111 | + final case class FlatMap[S[_], A, B](fa: Quasi[S, A], f: A => Quasi[S, B]) |
| 112 | + final case class Ap[S[_], A, B](ff: Quasi[S, A => B], fa: Quasi[S, A]) |
| 113 | + type Raise[S[_], E, A] = E |
| 114 | + final case class Handle[S[_], E, A](fe: E => Quasi[S, A]) |
| 115 | + //type Handle[S[_], E, A] = E => Quasi[S, A] |
| 116 | + |
| 117 | + def toConcur[S[_], A](quasi: Quasi[S, A]): Concur[S, A] = quasi |
| 118 | + def fromConcur[S[_], A](subseq: Concur[S, A]): Quasi[S, A] = subseq |
| 119 | + def toSubseq[S[_], A](quasi: Quasi[S, A]): Subseq[S, A] = quasi |
| 120 | + def fromSubseq[S[_], A](subseq: Subseq[S, A]): Quasi[S, A] = subseq |
| 121 | + |
| 122 | + def pure[S[_], A](a: A): Quasi[S, A] = |
| 123 | + CopK.unsafeApply[Effects[S], Pure[S, ?], A](0, a) |
| 124 | + |
| 125 | + def suspend[S[_], A](value: S[A]): Quasi[S, A] = |
| 126 | + CopK.unsafeApply[Effects[S], Suspend[S, ?], A](1, value) |
| 127 | + |
| 128 | + def flatMap[S[_], A, B](fa: Quasi[S, A])(f: A => Quasi[S, B]): Quasi[S, B] = |
| 129 | + CopK.unsafeApply[Effects[S], FlatMap[S, A, ?], B](2, FlatMap[S, A, B](fa, f)) |
| 130 | + |
| 131 | + def ap[S[_], A, B](ff: Quasi[S, A => B])(fa: Quasi[S, A]): Quasi[S, B] = |
| 132 | + CopK.unsafeApply[Effects[S], Ap[S, A, ?], B](2, Ap[S, A, B](ff, fa)) |
| 133 | + |
| 134 | + } |
| 135 | + |
| 136 | +} |
| 137 | + |
| 138 | +// example |
| 139 | +//#+cats |
| 140 | +import cats.implicits._ |
| 141 | +package quasi { |
| 142 | + |
| 143 | + object Example { |
| 144 | + |
| 145 | + def main(args: Array[String]): Unit = { |
| 146 | + |
| 147 | + trait MathOp[A] |
| 148 | + case class ConstInt(value: Int) extends MathOp[Int] |
| 149 | + case class Add[A](x: A, y: A) extends MathOp[A] |
| 150 | + case class Neg[A](x: A) extends MathOp[A] |
| 151 | + |
| 152 | + trait Math[F[_]] { underlying => |
| 153 | + def const(value: Int): F[Int] |
| 154 | + def add[A](x: A, y: A): F[A] |
| 155 | + def neg[A](x: A): F[A] |
| 156 | + |
| 157 | + final def mapK[G[_]](f: F ~> G): Math[G] = new Math[G] { |
| 158 | + def const(value: Int): G[Int] = f(underlying.const(value)) |
| 159 | + def add[A](x: A, y: A): G[A] = f(underlying.add(x, y)) |
| 160 | + def neg[A](x: A): G[A] = f(underlying.neg(x)) |
| 161 | + } |
| 162 | + } |
| 163 | + |
| 164 | + object Math { |
| 165 | + def quasi: Math[Quasi[MathOp, ?]] = new Math[Quasi[MathOp, ?]] { |
| 166 | + def const(value: Int): Quasi[MathOp, Int] = Quasi.liftF(ConstInt(value)) |
| 167 | + def add[A](x: A, y: A): Quasi[MathOp, A] = Quasi.liftF(Add(x, y)) |
| 168 | + def neg[A](x: A): Quasi[MathOp, A] = Quasi.liftF(Neg(x)) |
| 169 | + } |
| 170 | + |
| 171 | + def concur: Math[Concur[MathOp, ?]] = quasi.mapK[Concur[MathOp, ?]](Quasi.toConcur) |
| 172 | + def subseq: Math[Subseq[MathOp, ?]] = quasi.mapK[Subseq[MathOp, ?]](Quasi.toSubseq) |
| 173 | + } |
| 174 | + |
| 175 | + val math = Math.subseq |
| 176 | + |
| 177 | + val program0 = for { |
| 178 | + x <- math.const(1) |
| 179 | + y <- math.const(2) |
| 180 | + z <- math.add(x, y) |
| 181 | + } yield z |
| 182 | + |
| 183 | + val program1 = for { |
| 184 | + a <- math.const(100) |
| 185 | + b <- math.neg(a) |
| 186 | + } yield a + b |
| 187 | + |
| 188 | + val program2 = for { |
| 189 | + foo <- math.const(0) |
| 190 | + bar <- List(program0, program1).parSequence |
| 191 | + } yield bar.foldLeft(foo)(_ + _) |
| 192 | + |
| 193 | + scala.Predef.println(program2) |
| 194 | + |
| 195 | + } |
| 196 | + |
| 197 | + } |
| 198 | +} |
| 199 | +//#-cats |
0 commit comments