egglog 2.0.0

egglog is a language that combines the benefits of equality saturation and datalog. It can be used for analysis, optimization, and synthesis of programs. It is the successor to the popular rust library egg.
Documentation
; type checking for simply typed lambda calculus

(datatype Type 
  (TArr Type Type) ; t1 -> t2
)
(constructor TUnitConst () Type)
(let $TUnit (TUnitConst))

(datatype Expr 
  (Lam String Type Expr) ; lam x : t . e
  (App Expr Expr) 
  (Var String) 
)
(constructor MyUnitConst () Expr)
(let $MyUnit (MyUnitConst))

(datatype Ctx 
  (Cons String Type Ctx)
)
(constructor NilConst () Ctx)
(let $Nil (NilConst))

; ctx |- expr : type
(constructor typeof (Ctx Expr) Type)

; ctx |- () : unit
(rewrite (typeof ctx $MyUnit) $TUnit)

; ctx; x: t |- x : t
(rewrite (typeof (Cons x t ctx) (Var x)) t)

; ctx |- f :- t1 -> t2
; ctx |- e : t1
; -----------------
; ctx |- f e : t2

(rule (
  (= (typeof ctx (App f e)) t2)
)(
  (typeof ctx f)
  (typeof ctx e)
))

(rule (
  (= (typeof ctx (App f e)) t1)
  (= (typeof ctx f) (TArr (typeof ctx e) t2))
)(
  (union t1 t2)
))

; ctx |- x : t
; ------------------ y != x 
; ctx; y: t |- x : t

(rewrite (typeof (Cons y ty ctx) (Var x))
         (typeof ctx (Var x))
    :when ((!= x y)))

; ctx; x: t1 |- e : t2
; ------------------------------
; ctx |- lam x: t1. e : t1 -> t2

; rhs of rewrite creates demand
(rewrite (typeof ctx (Lam x t1 e))
         (TArr t1 (typeof (Cons x t1 ctx) e)))

; TEST
; ----

; lam x : unit, f : unit -> unit . f x
(let $e 
  (Lam "x" $TUnit 
       (Lam "f" (TArr $TUnit $TUnit)
            (App (Var "f") (Var "x")))))

; lam x : unit . x
(let $id (Lam "x" $TUnit (Var "x")))
(let $t-id (typeof $Nil $id))

; ($e () $id) = ()
(let $app-unit-id (App (App $e $MyUnit) $id))
(let $t-app (typeof $Nil $app-unit-id))

(let $free (Lam "x" $TUnit (Var "y")))
(let $t-free-ill (typeof $Nil $free))
(let $t-free-1 (typeof (Cons "y" $TUnit $Nil) $free))
(let $t-free-2 (typeof (Cons "y" (TArr (TArr $TUnit $TUnit) $TUnit) $Nil) $free))

(run 15)

(extract $t-id)
(check (= $t-id (TArr $TUnit $TUnit)))

(extract $t-app)
(check (= $t-app $TUnit))

(extract $t-free-1)
(check (= $t-free-1 (TArr $TUnit $TUnit)))
(extract $t-free-2)
(check (= $t-free-2 (TArr $TUnit (TArr (TArr $TUnit $TUnit) $TUnit))))
; this will err
; (extract $t-free-ill)