Skip to content

Instantly share code, notes, and snippets.

@nrinaudo
Last active January 10, 2025 21:30
Show Gist options
  • Save nrinaudo/64b3df262cb5abcdb813ea034e4ef901 to your computer and use it in GitHub Desktop.
Save nrinaudo/64b3df262cb5abcdb813ea034e4ef901 to your computer and use it in GitHub Desktop.
Intuition for a typed environment
// - Elem --------------------------------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------------------------------------
sealed trait Elem[X, XS <: Tuple]:
def get(haystack: XS): X
object Elem:
case class Here[X, XS <: Tuple]() extends Elem [X, X *: XS]:
def get(haystack: X *: XS) = haystack.head
case class There[H, X, T <: Tuple](elem: Elem[X, T]) extends Elem[X, H *: T]:
def get(haystack: H *: T) = elem.get(haystack.tail)
// - Types -------------------------------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------------------------------------
enum Type:
case Num
case Bool
object Type:
type Num = Num.type
type Bool = Bool.type
enum TypeRepr[X]:
case Num extends TypeRepr[Type.Num]
case Bool extends TypeRepr[Type.Bool]
// - Environment -------------------------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------------------------------------
case class Env[XS <: Tuple](data: List[Env.Binding[?, XS]]):
def lookup[X](name: String, repr: TypeRepr[X]): Either[String, Elem[X, XS]] =
data.find(_.name == name).toRight(s"Binding not found: $name").flatMap:
case Env.Binding(_, `repr`, location) => Right(location)
case _ => Left(s"Incorrect type: $name")
def bind[X](name: String, repr: TypeRepr[X]): Env[X *: XS] =
val newBinding = Env.Binding[X, X *: XS](name, repr, Elem.Here())
val newData: List[Env.Binding[?, X *: XS]] = data.map: binding =>
binding.copy(location = Elem.There(binding.location))
Env(newBinding :: newData)
object Env:
val empty: Env[EmptyTuple] = Env(List.empty)
case class Binding[X, XS <: Tuple](name: String, repr: TypeRepr[X], location: Elem[X, XS])
// - Demo --------------------------------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------------------------------------
object Run extends App:
val env = Env.empty
val env2 = env.bind("i", TypeRepr.Num)
val env3 = env2.bind("b", TypeRepr.Bool)
val env4 = env3.bind("j", TypeRepr.Num)
println(env2.lookup("i", TypeRepr.Num)) // Right(Here())
println(env4.lookup("i", TypeRepr.Num)) // Right(There(There(Here()))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment