add lambda-like special form

This commit is contained in:
mehbark 2023-06-14 22:51:42 -04:00
parent 180f03244a
commit 058cf26e89

View file

@ -611,6 +611,7 @@ pub fn simp(rules: &[Rule], mut expr: Sexp, step_limit: usize, complexity_limit:
for _ in 0..step_limit {
expr = expr
.apply_special_form::<Genslop>()
.apply_special_form::<LambdaLike>()
.apply_special_form::<App>()
.apply_special_form::<Log>()
.apply_special_form::<Let>()
@ -792,6 +793,80 @@ impl<'src> SpecialForm<'src> for App<'src> {
}
}
static LAMBDA_LIKE: Lazy<Symbol> =
Lazy::new(|| TABLE.lock().unwrap().intern("lambda-like").unwrap());
#[derive(Debug, Clone)]
struct LambdaLike<'src> {
lambda: &'src Sexp,
bindings: &'src [Sexp],
body: Option<&'src Sexp>,
}
impl<'src> SpecialForm<'src> for LambdaLike<'src> {
fn from_sexp(sexp: &'src Sexp) -> Option<Self> {
match sexp {
Sexp::Atom(_) => None,
Sexp::List(xs) => match &xs[..] {
[Sexp::Atom(lambda_like), lambda, Sexp::List(bindings), body]
if *lambda_like == *LAMBDA_LIKE =>
{
Some(Self {
lambda,
bindings,
body: Some(body),
})
}
[Sexp::Atom(lambda_like), lambda, Sexp::List(bindings)]
if *lambda_like == *LAMBDA_LIKE =>
{
Some(Self {
lambda,
bindings,
body: None,
})
}
_ => None,
},
}
}
// (lambda () body) -> (lambda () body)
// it's sort of incorrect (do zero arg functions exist? actual question), but i think i'll actually do:
// (lambda () body) -> body
// (lambda (a) body) -> (lambda a body)
// (lambda (a) body) -> (lambda a body)
// (lambda (a b) body) -> (lambda a (lambda b body))
fn eval(self) -> Sexp {
let Self {
lambda,
bindings,
body,
} = self;
if let Some(body) = body {
let mut out = body.clone();
for binding in bindings.iter().rev() {
out = Sexp::List(vec![lambda.clone(), binding.clone(), out]);
}
out
} else if let Some(body) = bindings.last() {
let mut out = body.clone();
for binding in bindings.iter().rev().skip(1) {
out = Sexp::List(vec![lambda.clone(), binding.clone(), out]);
}
out
} else {
// HACK: bad?
Sexp::nil()
}
}
}
pub fn make_rule(sexp: &Sexp) -> Option<Rule> {
match sexp {
Sexp::List(xs) => match &xs[..] {