Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save kevinmeredith/71d22061708f906cf7e0 to your computer and use it in GitHub Desktop.
Save kevinmeredith/71d22061708f906cf7e0 to your computer and use it in GitHub Desktop.
// let's imagine you have an algebra that has a constructor like the following
sealed trait Algebra[A]
case class Ext[E, A](e: E, f: E => A) extends Algebra[A]
/*
* Not at all an uncommon pattern! Basically, this is going to show up any time you're
* doing GADTs or GADT-like things, or any sort of type-aligned sequence (in any form).
* The problem is that the pattern matcher affixes types in a linear fashion, and thus
* will not unify the solution to E between the two parameters. For example:
*/
def run[A](alg: Algebra[A]): A = alg match {
case Ext(e, f) => f(e) // does not compile!
}
/*
* It doesn't compile because scalac can't figure out that the E it solved for when it
* looked at the first parameter is the same E when it comes to the second parameter.
* However, it CAN solve for the E in the enclosing Ext type, because it's not being asked
* to fix the type while it is in the process of fixing types at that level (i.e. the type
* is solely derived from an "inner" level of the pattern). For this reason, we can use
* the following workaround:
*/
def run[A](alg: Algebra[A]): A = alg match {
case a @ Ext(e, _) => a.f(e) // yay!
}
/*
* This works just fine! And it will work any time you use this sort of pattern.
*/
@kevinmeredith
Copy link
Author

L12's run compiles for me:

$scala
Welcome to Scala 2.12.0-M3 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_51).
Type in expressions for evaluation. Or try :help.

scala> sealed trait Algebra[A]
defined trait Algebra

scala> case class Ext[E, A](e: E, f: E => A) extends Algebra[A]
defined class Ext

scala> def run[A](alg: Algebra[A]): A = alg match {
     |   case Ext(e, f) => f(e)        // does not compile! 
     | }
run: [A](alg: Algebra[A])A

scala> val alg: Algebra[Int] = Ext[String, Int]("foo", _ => 42)
alg: Algebra[Int] = Ext(foo,$$Lambda$2430/1074630954@9f6e406)

scala> run(alg)
res1: Int = 42

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment