Typecheckeando tus Lambdas en 10* minutos

Julián Antonielli

@jjant/@_jjant

Un lenguaje muy sencillo

Expresiones

e ::= zero     -- Cero
    | succ e   -- Sucesor
    | pred e   -- Predecesor
    | isZero e
    | true 
    | false
    | if e then e else e
data Expr
  = Zero
  | Succ Expr
  | Pred Expr
  | IsZero Expr
  | Tru
  | Fals
  | If Expr Expr Expr
  deriving (Show, Eq)
> if isZero (succ zero) then true else false
=> false : Boolean
> succ (succ zero)
=> 2 : Natural

Ejemplos

Tipado

Bool

Nat

T ::= Natural
    | Boolean
data Type
  = Natural
  | Boolean

Tipado

Bool

check :: Expr -> Maybe Type
check Tru = Just Boolean
check Fals = Just Boolean
check (If b t e) = do
  tyB <- check b
  tyT <- check t
  tyE <- check e
  case (tyB, tyT == tyE) of
    (Boolean, True) -> Just tyT
    _ -> Nothing

Tipado

Nat

check :: Expr -> Maybe Type
check Zero = Just Natural
check (Succ x) = do
  ty <- check x
  if ty == Natural
    then Just Natural
    else Nothing
check (IsZero x) = do
  ty <- check x
  if ty == Natural
    then Just Boolean
    else Nothing
check (Pred x) = ...

Demo!

Observación

No hablamos de evaluación, pero no necesitamos evaluar nada durante el typechecking.

Cálculo Lambda Simplemente Tipado

Expresiones

e ::= v           -- Variable
    | 0, 1, 2..   -- Naturals
    | True, False -- Bools
    | λ x : T. e  -- Lambda
    | e1 e2       -- Aplicación
data Expr
  = Var Name
  | Lit Ground
  | App Expr Expr
  | Lam Name Type Expr

data Ground
  = LInt Int
  | LBool Bool

> (\x : Int . x) 23
=> 23
> (\x : Int . \y : Bool . x) 12 True
12

Ejemplos

> False
=> False

Tipado

T ::= Natural
    | Boolean
    | T1 -> T2
data Type
  = TInt
  | TBool
  | TArr Type Type

Tipado

type Context =
    [(Name, Type)]
check :: Expr -> Either TypeError Type

Antes

Ahora

check :: Expr -> Context -> Either TypeError Type

Tipado

check :: Expr -> Context -> Either TypeError Type
check (Var n) ctx = do
  case lookup n ctx of
    Just ty -> pure ty
    Nothing -> Left $ "Variable " <> n <> " not in scope!"

Variables

Tipado

check :: Expr -> Context -> Either TypeError Type
check (Lam ty var body) ctx = do
  rangeT <- check body ((var, ty) : ctx)
  pure (TArr ty rangeT)

Lambdas

Tipado

check :: Expr -> Context -> Either TypeError Type
check (App term1 term2) ctx = do
  ty1 <- check term1 ctx
  ty2 <- check term2 ctx
  case ty1 of
    Func domain range ->
      if domain == ty2
        then pure range
        else Left ("Wrong domain, expected " <> show domain <> " but got " <> show ty2)
 
    _ -> Left ("Expected " <> show term1 <> " to be a function")

Aplicación

Tipado

check :: Expr -> Context -> Either TypeError Type
check (Lit l) _ =
  case l of
    LInt _ -> TInt
    LBool _ -> TBool

Literales

Lo mismo de antes

Y Haskell? Que nos falta?

Hindley-Milner Type System

  • (Algo de) Polimorfismo
     
  • ADTs
     
  • Case expressions
     
  • Typeclasses

Recursos

- Type inference from scratch, f(by) 2019: https://www.youtube.com/watch?v=ytPAlhnAKro


- Types and Programming Languages, Benjamin C. Pierce


- Stitch: The Sound Type-Indexed Type Checker: https://www.youtube.com/watch?v=XJ8hm3Tq2k8


- A tutorial implementation of a dependently typed Lambda Calculus: https://www.andres-loeh.de/LambdaPi/LambdaPi.pdf

Evaluación

Small-step semantics

Typechecker

By jjant

Typechecker

  • 359