Last active
July 4, 2016 05:29
-
-
Save blast-hardcheese/0d4a65493810c7cc47bbe998f3af28ce to your computer and use it in GitHub Desktop.
Type inference question in Cats
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
sealed trait ControlPanel[T] | |
case object ButtonPressed extends ControlPanel[Button] | |
case object StopEnabled extends ControlPanel[Unit] | |
case object StopDisabled extends ControlPanel[Unit] | |
case object CurrentFloor extends ControlPanel[Int] | |
sealed trait ElevatorControl[T] | |
case object GetFloor extends ElevatorControl[Int] | |
case class QueueFloor(x: Int) extends ElevatorControl[Unit] | |
trait FreeCTest1Interp { | |
implicit val controlPanelInterp = new NaturalTransformation[ControlPanel, Id] { | |
def apply[A](fa: ControlPanel[A]): Id[A] = fa match { | |
case ButtonPressed => Button("Floor 2") | |
case StopEnabled => println("Stop enabled") | |
case StopDisabled => println("Stop disabled") | |
case CurrentFloor => 2 | |
} | |
} | |
implicit val elevatorControlInterp = new NaturalTransformation[ElevatorControl, Id] { | |
def apply[A](fa: ElevatorControl[A]): Id[A] = fa match { | |
case GetFloor => 2 | |
case QueueFloor(floor) => () | |
} | |
} | |
} |
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
name := "free-experiments" | |
scalaVersion := "2.11.8" | |
libraryDependencies += "org.typelevel" %% "cats" % "0.6.0" |
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.Id | |
import cats.arrow.NaturalTransformation | |
import cats.data.Coproduct | |
import cats.free.{ Coyoneda, Free } | |
import cats.implicits._ | |
import scala.language.higherKinds | |
import Coproduct.{ leftc, rightc } | |
case class Button(label: String) | |
trait FreeCSupport { | |
type FreeC[F[_], A] = Free[({ type CoF[T] = Coyoneda[F,T] })#CoF,A] | |
def liftFC[F[_], A](value: F[A]): FreeC[F, A] = Free.liftF[({ type CoF[α] = Coyoneda[F, α] })#CoF, A](Coyoneda.lift[F, A](value)) | |
def runFC[F[_], A](prog: FreeC[F, A])(implicit interp: NaturalTransformation[F, Id]): A = { | |
prog.go { sfsa: Coyoneda[F, FreeC[F,A]] => | |
sfsa.transform(interp).run | |
} | |
} | |
implicit def combineNT[F[_], G[_], H[_]](implicit f: NaturalTransformation[F, H], g: NaturalTransformation[G, H]) = new NaturalTransformation[({ type FG[A] = Coproduct[F, G, A] })#FG, H] { | |
def apply[A](fga: Coproduct[F, G, A]): H[A] = { | |
fga.fold(f, g) | |
} | |
} | |
implicit def liftXorL[F[_], G[_], T](x: F[T]): F[T] Xor G[T] = Xor.left(x) | |
implicit def liftXorR[F[_], G[_], T](x: G[T]): F[T] Xor G[T] = Xor.right(x) | |
implicit def liftCoL[F[_], G[_], T](x: F[T]): Coproduct[F, G, T] = Coproduct(x) | |
implicit def liftCoR[F[_], G[_], T](x: G[T]): Coproduct[F, G, T] = Coproduct(x) | |
} |
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
object FreeCTest1 extends App with FreeCSupport with FreeCTest1Interp { | |
// Works, using FreeC only, no Coproduct | |
val prog1: FreeC[ControlPanel, Int] = for { | |
button <- liftFC(ButtonPressed) | |
_ <- liftFC(StopEnabled) | |
_ <- liftFC(StopDisabled) | |
currentFloor <- liftFC(CurrentFloor) | |
} yield { println(button); currentFloor } | |
// Works when specifying all types everywhere. | |
def prog(interp: NaturalTransformation[({ type CE[A] = Coproduct[ControlPanel, ElevatorControl, A] })#CE, Id]): Int = { | |
implicit def liftCP[T](value: ControlPanel[T]) = liftFC[({ type CE[A] = Coproduct[ControlPanel, ElevatorControl, A] })#CE, T](value) | |
implicit def liftEC[T](value: ElevatorControl[T]) = liftFC[({ type CE[A] = Coproduct[ControlPanel, ElevatorControl, A] })#CE, T](value) | |
implicit def lift[F[_], T](x: F[T])(implicit lifter: F[T] => FreeC[({ type CE[A] = Coproduct[ControlPanel, ElevatorControl, A] })#CE, T]) = lifter(x) | |
val _prog = for { | |
button <- ButtonPressed | |
currentFloor2 <- GetFloor | |
currentFloor <- CurrentFloor | |
} yield { println(button); currentFloor2 } | |
runFC[({ type CE[A] = Coproduct[ControlPanel, ElevatorControl, A] })#CE, Int](_prog)(interp) | |
} | |
println(prog(combineNT[ControlPanel, ElevatorControl, Id])) | |
// Simple example of the above | |
val coValue = Coyoneda.lift[({ type FG[A] = Coproduct[ControlPanel, ElevatorControl, A] })#FG, Button](leftc(ButtonPressed)) | |
val res = coValue.transform(combineNT).run | |
println(res) | |
} |
(This is a compilation error for revision 4)
[error] .../src/main/scala/App.scala:115: no type parameters for method runFC: (prog: FreeCTest1.FreeC[F,A])(implicit interp: cats.arrow.NaturalTransformation[F,cats.Id])A exist so that it can be applied to arguments (cats.free.Free[[T]cats.free.Coyoneda[[A]cats.data.Coproduct[ControlPanel,ElevatorControl,A],T],Int])
[error] --- because ---
[error] argument expression's type is not compatible with formal parameter type;
[error] found : cats.free.Free[[T]cats.free.Coyoneda[[A]cats.data.Coproduct[ControlPanel,ElevatorControl,A],T],Int]
[error] required: FreeCTest1.FreeC[?F,?A]
[error] (which expands to) cats.free.Free[[T]cats.free.Coyoneda[?F,T],?A]
[error] runFC(_prog)(interp)
[error] ^
[error] .../src/main/scala/App.scala:115: type mismatch;
[error] found : cats.free.Free[[T]cats.free.Coyoneda[[A(in type CE)]cats.data.Coproduct[ControlPanel,ElevatorControl,A(in type CE)],T],Int]
[error] required: FreeCTest1.FreeC[F,A(in method runFC)]
[error] (which expands to) cats.free.Free[[T]cats.free.Coyoneda[F,T],A(in method runFC)]
[error] runFC(_prog)(interp)
[error] ^
[error] two errors found
[error] (compile:compileIncremental) Compilation failed
[error] Total time: 1 s, completed Jul 3, 2016 3:38:40 PM
Turns out the issue was SI-2712, and https://github.com/milessabin/si2712fix-plugin made short work of it.
Experiments are continued at https://github.com/blast-hardcheese/scala-free-playground.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
(This was a compilation error for revision 2)