MCPcopy Create free account
hub / github.com/argumentcomputer/ix / cheap_beta_reduce

Function cheap_beta_reduce

crates/kernel/src/subst.rs:512–588  ·  view source on GitHub ↗

Cheap beta reduction: peephole-reduce `App(λ...λ. body, args)` shapes without invoking the full [`subst`] machinery in trivial cases. Mirrors `lean4lean`'s `Expr.cheapBetaReduce` (refs/lean4lean/Lean4Lean/Instantiate.lean:8-27) and the C++ kernel's `cheap_beta_reduce` (refs/lean4/src/kernel/instantiate.cpp:211). For a spine `App(λx_0 ... λx_{n-1}. body, a_0, ..., a_{m-1})` we peel `i = min(n, m)

(
  env: &mut InternTable<M>,
  e: &KExpr<M>,
)

Source from the content-addressed store, hash-verified

510 /// referenced by many variables; spine args survive multiple machine
511 /// re-entries), and without a global content-addressed memo this is
512 /// what keeps each shared closure's substitution from re-running.
513 readback: OnceCell<KExpr<M>>,
514}
515
516impl<M: KernelMode> Clo<M> {
517 pub(crate) fn new(e: KExpr<M>, env: MEnv<M>) -> Self {
518 Clo { e, env, readback: OnceCell::new() }
519 }
520
521 /// Closure over the empty environment (a plain expression).
522 pub(crate) fn closed(e: KExpr<M>) -> Self {
523 Clo::new(e, MEnv::empty())
524 }
525}
526
527struct MEnvNode<M: KernelMode> {
528 head: Arc<Clo<M>>,
529 tail: MEnv<M>,
530}
531
532/// Persistent cons-list environment: O(1) push with structural sharing
533/// across the closures captured at each binder. `len` is carried on the
534/// handle — recomputing it per suffix was a measured cost on the IxVM
535/// port of this machine.
536pub(crate) struct MEnv<M: KernelMode> {
537 node: Option<Arc<MEnvNode<M>>>,
538 len: u64,
539}
540
541// Manual impl: `#[derive(Clone)]` would demand `M: Clone`.
542impl<M: KernelMode> Clone for MEnv<M> {
543 fn clone(&self) -> Self {
544 MEnv { node: self.node.clone(), len: self.len }
545 }
546}
547
548impl<M: KernelMode> MEnv<M> {
549 pub(crate) fn empty() -> Self {
550 MEnv { node: None, len: 0 }
551 }
552
553 pub(crate) fn len(&self) -> u64 {
554 self.len
555 }
556
557 pub(crate) fn push(&self, c: Arc<Clo<M>>) -> Self {
558 MEnv {
559 node: Some(Arc::new(MEnvNode { head: c, tail: self.clone() })),
560 len: self.len + 1,
561 }
562 }
563
564 /// O(i) cons-list walk; `i` must be `< self.len()`. Machine variable
565 /// lookups are typically near the front (recently pushed args).
566 pub(crate) fn get(&self, i: u64) -> &Arc<Clo<M>> {
567 let mut node = self.node.as_ref().expect("MEnv::get out of range");
568 let mut i = i;
569 while i > 0 {

Calls 7

pushMethod · 0.80
lbrMethod · 0.80
intern_exprMethod · 0.80
appFunction · 0.70
cloneMethod · 0.45
dataMethod · 0.45
lenMethod · 0.45