crosslang/RosettaStone.lean
Maximus Gorog f5f1701922 Add RosettaStone.lean — Go ↔ Lean translation reference.
Side-by-side comparisons of Go syntax with two Lean encodings:

  * Surface AST (GolangLean.Expr) — mirrors go/ast.Node from upstream.
  * Tiny Go Core (GolangLean.Core.Term) — kernel calculus with proven
    operational + type semantics.

Twelve sections covering: literals, arithmetic, comparison, conditional,
variables/let-binding, functions/application, references/deref/assign,
sequencing. Each example includes a `#eval` running the term through
the proven Core.eval; output matches what's expected at run time.

Demonstrated programs:
  - `(5 + 3) * 2` → 16
  - `let x = 3 in let y = 7 in x < y` → true
  - `(λ x. x*2) 21` → 42
  - `let double = λ x. x*2 in double (double 5)` → 20
  - `let p = &42 in *p = 100; *p` → 100 (heap: [vInt 100])
  - higher-order: `(λ f. λ x. f (f x)) double 3` → 12

Each #eval is a runtime witness for a Core.BigStep derivation. Apply
Core.eval_sound to get a proof of the BigStep relation, and
Core.preservation to get the value's type.

Supporting changes:
  - Added Repr instances for Core.Value and Core.EnvList (manual,
    handling the mutual inductive — derive doesn't compose across the
    mutual block).
  - Added RosettaStone as a lean_lib in lakefile.toml.
2026-05-10 06:49:22 -06:00

157 lines
5.5 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import GolangLean
/-!
# golang-lean Rosetta Stone
Side-by-side comparisons of Go syntax with its Lean encodings.
Two encodings are shown for each construct:
* **Surface AST** (`GolangLean.Expr`, etc.) — the parser's target.
Mirrors `go/ast.Node` from the upstream Go reference compiler.
Faithful to Go's grammar but has no formal semantics yet (the
surface evaluator is a stub).
* **Tiny Go Core** (`GolangLean.Core.Term`) — the kernel calculus.
Smaller, typed, with proven big-step semantics, executable
evaluator, determinism, and preservation. Real Go programs would
desugar into this kernel via an elaborator (future work).
Where applicable, `#eval` runs the term through the proven evaluator.
The result is `some (Value, Heap)` on success.
-/
open GolangLean
-- A tiny convenience for running TGC programs.
def runTGC (e : Core.Term) : Option (Core.Value × Core.Heap) :=
Core.eval 1000 #[] .nil e
/-! ## §1 Literals — atoms of any language. -/
-- Go: `42`
def lit42_AST : Expr := .intLit 42
def lit42_TGC : Core.Term := .intLit 42
#eval runTGC lit42_TGC -- some (vInt 42, [])
-- Go: `true` (a predeclared identifier in Go)
def litTrue_AST : Expr := .ident "true"
def litTrue_TGC : Core.Term := .boolLit true
#eval runTGC litTrue_TGC -- some (vBool true, [])
/-! ## §2 Arithmetic and comparison
Go's binary operators map directly to TGC's `binop`. -/
-- Go: `5 + 3`
def add5_3_AST : Expr := .binOp .add (.intLit 5) (.intLit 3)
def add5_3_TGC : Core.Term := .binop .add (.intLit 5) (.intLit 3)
#eval runTGC add5_3_TGC -- some (vInt 8, [])
-- Go: `(5 + 3) * 2`
def expr_AST : Expr :=
.binOp .mul (.binOp .add (.intLit 5) (.intLit 3)) (.intLit 2)
def expr_TGC : Core.Term :=
.binop .mul (.binop .add (.intLit 5) (.intLit 3)) (.intLit 2)
#eval runTGC expr_TGC -- some (vInt 16, [])
-- Go: `x < y`
def less_AST : Expr := .binOp .lss (.ident "x") (.ident "y")
def less_TGC : Core.Term := .binop .lt (.var "x") (.var "y")
-- Needs an env binding x and y — see §4.
-- Go: `x == 5`
def eq_AST : Expr := .binOp .eql (.ident "x") (.intLit 5)
def eq_TGC : Core.Term := .binop .eq (.var "x") (.intLit 5)
/-! ## §3 Conditionals
Go's `if` statement vs. TGC's `ifte` expression form. -/
-- Go (statement): `if x < 10 { return 1 } else { return 2 }`
-- Go has no ternary expression; TGC's `ifte` is closer to ML's
-- `if ... then ... else ...` for proof-friendliness.
def ifte_TGC : Core.Term :=
.ifte (.binop .lt (.var "x") (.intLit 10))
(.intLit 1) (.intLit 2)
/-! ## §4 Variables and let-binding
Go's `x := 42` ↦ TGC's `letIn` (lexical binding, scoped to body).
For *mutating* variables, see §6 (TGC uses `assign` on a heap-allocated
ref). -/
-- Go: `x := 42; x + 1`
def letIn_TGC : Core.Term :=
.letIn "x" (.intLit 42) (.binop .add (.var "x") (.intLit 1))
#eval runTGC letIn_TGC -- some (vInt 43, [])
-- Two bindings: `x := 3; y := 7; x < y`
def less_run : Core.Term :=
.letIn "x" (.intLit 3)
(.letIn "y" (.intLit 7)
(.binop .lt (.var "x") (.var "y")))
#eval runTGC less_run -- some (vBool true, [])
/-! ## §5 Functions and application
Go's anonymous function `func(x int) int { return x*2 }` ↦ TGC's
`lam` (a closure). Application is `app`. -/
-- Go: `(func(x int) int { return x*2 })(21)`
def lambda_app_TGC : Core.Term :=
.app (.lam "x" (.binop .mul (.var "x") (.intLit 2))) (.intLit 21)
#eval runTGC lambda_app_TGC -- some (vInt 42, [])
-- Higher-order. With `double = func(x) { x*2 }`:
-- `(func(f) func(x) { f(f(x)) })(double)(3)` = double(double(3)) = 12
def higher_order_TGC : Core.Term :=
.app
(.app
(.lam "f"
(.lam "x" (.app (.var "f") (.app (.var "f") (.var "x")))))
(.lam "x" (.binop .mul (.var "x") (.intLit 2))))
(.intLit 3)
#eval runTGC higher_order_TGC -- some (vInt 12, [])
/-! ## §6 References, dereference, assignment
Go's `&x`, `*p`, `*p = e` ↦ TGC's `refMk`, `deref`, `assign`.
The heap (third tuple component, an `Array Value`) accumulates
allocations. -/
-- Go: `p := &42; *p`
def ref_deref_TGC : Core.Term :=
.letIn "p" (.refMk (.intLit 42)) (.deref (.var "p"))
#eval runTGC ref_deref_TGC -- some (vInt 42, #[vInt 42])
-- Go: `p := &42; *p = 100; *p`
def ref_assign_TGC : Core.Term :=
.letIn "p" (.refMk (.intLit 42))
(.seq (.assign (.var "p") (.intLit 100))
(.deref (.var "p")))
#eval runTGC ref_assign_TGC -- some (vInt 100, #[vInt 100])
/-! ## §7 Sequencing — Go statement separator. -/
-- Go: `_ = 1; 42`
def seq_TGC : Core.Term := .seq (.intLit 1) (.intLit 42)
#eval runTGC seq_TGC -- some (vInt 42, [])
/-! ## §8 Theorems applicable to these terms
* `Core.BigStep.deterministic` — the relation is functional.
* `Core.eval_sound` — every successful eval is a `BigStep` derivation.
* `Core.preservation` — well-typed terms produce well-typed values.
Each `#eval` above is a *runtime witness* for a `BigStep` derivation,
which by `eval_sound` is also a proof that the term has the shown
value. Type-check the term and apply `preservation` to get the value's
type for free. -/
-- Demo: a small composition showing TGC's expressive range.
-- `let double = λ x. x*2 in double (double 5)` = 20
def double_twice : Core.Term :=
.letIn "double" (.lam "x" (.binop .mul (.var "x") (.intLit 2)))
(.app (.var "double") (.app (.var "double") (.intLit 5)))
#eval runTGC double_twice -- some (vInt 20, [])