letExpr

-- let-expressions: local definitions with judgemental transparency.
--
-- The body of `let x ≔ e in b` is typed under x AND its unfolding
-- equation x ≡ e (docs/NovaFoundation.txt, el-let — the strong,
-- definition-carrying form), so facts stated at the abbreviation
-- discharge against facts about its unfolding silently: no manual
-- unfolding, no transport, no plumbing. From the outside a let IS its
-- unfolding (el-let-beta), so lemmas about a let-using definition
-- compute as if the let were never there.

import nat (+)

-- checking mode, nested lets, an annotated definiens
-- (`let x : T ≔ e in b` is sugar for `let x ≔ (e : T) in b`)
def four :  
  let one :   S Z in
  let two  one + one in
  two + two

-- a let in INFERENCE position (an application head): the body's type
-- is inferred and the definiens substituted back into it
def three :   (let f  (λx. S x :   ) in f) (S (S Z))

-- transparency inside the body: the ⋆ pays an equation stated at the
-- ABBREVIATION m while the goal is stated at its unfolding — both
-- gaps close through the let's own hypothesis (m ≡ n + n), not by β
-- (m is a variable, not a redex)
def letShared : (n : )  (n + n) + Z  n + n   
  λn. let m  n + n in ( : m + Z  m  )

-- the outside view: a let-expression is judgementally its unfolding
def fourUnfolds : four  S (S (S (S Z)))    
def threeUnfolds : three  S (S (S Z))