add lambda-like special form
This commit is contained in:
parent
180f03244a
commit
058cf26e89
1 changed files with 75 additions and 0 deletions
75
src/main.rs
75
src/main.rs
|
@ -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[..] {
|
||||
|
|
Loading…
Reference in a new issue