- | List the sub-expressions and their environments. 'Let' bindings are handled first, to make sure
-- that these are always treated as one-shot binders. Next, the supplied 'MkSubEnv' is given the
-- chance to compute the result. If it doesn't, the expression is handled in a standard way.
subTermsEnv :: Project Let dom
    => PrjDict dom
    -> MkSubEnv dom
    -> Env dom
    -> dom sig
    -> Args (AST dom) sig
    -> [(ASTE dom, Env dom)]
subTermsEnv pd ed env lt (a :* (Sym lam :$ b) :* Nil)
    | Just Let <- prj lt
    , Just v   <- prjLambda pd lam
    = [(ASTE a, env), (ASTE b, lamEnvOneShot v env)]

subTermsEnv :: Project Let dom
    => PrjDict dom
    -> MkSubEnv dom
    -> Env dom
    -> dom sig
    -> Args (AST dom) sig
    -> [(ASTE dom, Env dom)]
subTermsEnv pd ed env lt (a :* (Sym lam :$ b) :* Nil)
    | Just Let <- prj lt
    , Just v   <- prjLambda pd lam
    = [(ASTE a, env), (ASTE b, lamEnvOneShot v env)]
subTermsEnv pd ed env lt (a :* (Sym lam :$ b) :* Nil)
    | Just Let <- prj lt
    , Just v   <- prjLambda pd lam
    = [(ASTE a, env), (ASTE b, lamEnvOneShot v env)]