Skip to content

Instantly share code, notes, and snippets.

@Kakadu
Created January 25, 2021 23:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Kakadu/8692e4aaa50215d54935ec9d8ee3d313 to your computer and use it in GitHub Desktop.
Save Kakadu/8692e4aaa50215d54935ec9d8ee3d313 to your computer and use it in GitHub Desktop.
Scala 2 with or type
sealed trait AST
case class ConstInt(x: Int) extends AST
case class ConstDouble(x: Double) extends AST
case class SomethingElse() extends AST
type ¬[A] = A => Nothing
type ∨[T, U] = ¬[¬[T] with ¬[U]]
type ¬¬[A] = ¬[¬[A]]
type |∨|[T, U] = { type λ[X] = ¬¬[X] <:< (T ∨ U) }
def size[T: (Int |∨| String)#λ](t: T) =
t match {
case i: Int => i
case s: String => s.length
}
object ANumber {
def unapply[T : (Int |∨| String)#λ](ast: AST): Option[T] = {
ast match {
case ConstInt(n: Int)=> Some(n)
/*
type mismatch;
found : n.type (with underlying type Int)
required: T
*/
case ConstDouble(n)=> Some(n)
case _ => None
}
}
}
def interpret(x: AST) = {
x match {
case ANumber(int_or_double) => "number"
case SomethingElse() => "???"
}
}
@bash-spbu
Copy link

package example

sealed trait AST

case class ConstInt(x: Int) extends AST

case class ConstDouble(x: Double) extends AST

case class SomethingElse() extends AST

object T {
  type ¬[A] = A => Nothing
  type [T, U] = ¬[¬[T] with ¬[U]]
  type ¬¬[A] = ¬[¬[A]]
  type |∨|[T, U] = {
    type λ[X] = ¬¬[X] <:< (TU)
  }

  implicit def axiom[A]: A =:= ¬¬[A] = ???

  @inline def toUnion[T, U](x: T): ∨[T, U] =
    implicitly[(T || U)#λ[T]].apply(implicitly[T =:= ¬¬[T]].apply(x))

  @inline def fromUnion[L, R, S](t: ∨[L, R])(leftProj: L => S, rightProj: R => S) =
    t match {
      case l: L => leftProj(l)
      case r: R => rightProj(r)
    }

  object ANumber {
    def unapply(ast: AST): Option[IntDouble] = {
      ast match {
        case ConstInt(n) => Some(toUnion[Int, Double](n))
        case ConstDouble(n) => Some(toUnion[Double, Int](n))
        case _ => None
      }
    }
  }

  def size[T: (Int || String)#λ](t: T) =
    t match {
      case i: Int => i
      case s: String => s.length
    }

  def interpret(x: AST) = {
    x match {
      case ANumber(int_or_double) =>
        fromUnion(int_or_double)(
          _.toOctalString, // toOctalString belongs to Int and not for Double so we proved that it is Int
          _.isInfinity 
        )
      case SomethingElse() => "???"
    }
  }

  def main(args: Array[String]): Unit = {

  }
}

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