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.
This commit is contained in:
parent
ed636a1aa2
commit
f5f1701922
3 changed files with 177 additions and 0 deletions
|
|
@ -33,6 +33,23 @@ mutual
|
|||
|
||||
end
|
||||
|
||||
mutual
|
||||
partial def Value.repr : Value → Std.Format
|
||||
| .vUnit => "vUnit"
|
||||
| .vInt n => f!"vInt {n}"
|
||||
| .vBool b => f!"vBool {b}"
|
||||
| .vClos x _ _ => f!"<closure λ {x}. ...>"
|
||||
| .vLoc n => f!"vLoc {n}"
|
||||
partial def EnvList.repr : EnvList → Std.Format
|
||||
| .nil => "[]"
|
||||
| .cons k v r => f!"{k}↦{Value.repr v} :: {EnvList.repr r}"
|
||||
end
|
||||
|
||||
instance : Repr Value where
|
||||
reprPrec v _ := Value.repr v
|
||||
instance : Repr EnvList where
|
||||
reprPrec env _ := EnvList.repr env
|
||||
|
||||
abbrev Env := EnvList
|
||||
abbrev Heap := Array Value
|
||||
|
||||
|
|
|
|||
157
RosettaStone.lean
Normal file
157
RosettaStone.lean
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
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, [])
|
||||
|
|
@ -5,6 +5,9 @@ defaultTargets = ["golang-lean"]
|
|||
[[lean_lib]]
|
||||
name = "GolangLean"
|
||||
|
||||
[[lean_lib]]
|
||||
name = "RosettaStone"
|
||||
|
||||
[[lean_exe]]
|
||||
name = "golang-lean"
|
||||
root = "Main"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue