use polytype::TypeSchema;
use std::collections::VecDeque;
use std::fmt;
use std::sync::Arc;
use lambda::{Expression, Language};
pub fn eval<V, E>(
dsl: &Language,
expr: &Expression,
evaluator: &Arc<E>,
inps: &[V],
) -> Result<V, E::Error>
where
V: Clone + PartialEq + Send + Sync,
E: Evaluator<Space = V>,
{
ReducedExpression::new(dsl, expr).eval_inps(evaluator, inps)
}
pub fn lazy_eval<V, E>(
dsl: &Language,
expr: &Expression,
evaluator: &Arc<E>,
inps: &[V],
) -> Result<V, E::Error>
where
V: Clone + PartialEq + Send + Sync,
E: LazyEvaluator<Space = V>,
{
ReducedExpression::new(dsl, expr).lazy_eval_inps(evaluator, inps)
}
pub trait Evaluator: Sized + Sync {
type Space: Clone + PartialEq + Send + Sync;
type Error: Clone + Sync;
fn evaluate(&self, primitive: &str, inps: &[Self::Space]) -> Result<Self::Space, Self::Error>;
fn lift(&self, _f: LiftedFunction<Self::Space, Self>) -> Result<Self::Space, ()> {
Err(())
}
}
pub trait LazyEvaluator: Sized + Sync {
type Space: Clone + PartialEq + Send + Sync;
type Error: Clone + Sync;
fn lazy_evaluate(
&self,
primitive: &str,
inps: &[LiftedLazyFunction<Self::Space, Self>],
) -> Result<Self::Space, Self::Error>;
fn lift(&self, _f: LiftedLazyFunction<Self::Space, Self>) -> Result<Self::Space, ()> {
Err(())
}
}
pub struct SimpleEvaluator<V, R, F>(F, ::std::marker::PhantomData<(R, V)>);
impl<V, R, F> SimpleEvaluator<V, R, F>
where
V: Clone + PartialEq + Send + Sync,
R: Clone + Sync,
F: Fn(&str, &[V]) -> Result<V, R>,
{
pub fn of(f: F) -> Self {
SimpleEvaluator(f, ::std::marker::PhantomData)
}
}
impl<V, R, F> Evaluator for SimpleEvaluator<V, R, F>
where
V: Clone + PartialEq + Send + Sync,
R: Clone + Sync,
F: Fn(&str, &[V]) -> Result<V, R> + Sync,
{
type Space = V;
type Error = R;
fn evaluate(&self, primitive: &str, inps: &[Self::Space]) -> Result<Self::Space, Self::Error> {
(self.0)(primitive, inps)
}
}
pub struct LiftedFunction<V: Clone + PartialEq + Send + Sync, E: Evaluator<Space = V>>(
Arc<ReducedExpression<V>>,
Arc<E>,
Arc<VecDeque<ReducedExpression<V>>>,
);
impl<V, E> LiftedFunction<V, E>
where
E: Evaluator<Space = V>,
V: Clone + PartialEq + Send + Sync,
{
pub fn eval(&self, xs: &[V]) -> Result<V, E::Error> {
self.0.eval_inps_with_env(&self.1, &self.2, xs)
}
}
impl<V, E> Clone for LiftedFunction<V, E>
where
E: Evaluator<Space = V>,
V: Clone + PartialEq + Send + Sync,
{
fn clone(&self) -> Self {
LiftedFunction(self.0.clone(), self.1.clone(), self.2.clone())
}
}
impl<V, E> PartialEq for LiftedFunction<V, E>
where
E: Evaluator<Space = V>,
V: Clone + PartialEq + Send + Sync,
{
fn eq(&self, other: &LiftedFunction<V, E>) -> bool {
self.0 == other.0 && self.2 == other.2
}
}
impl<V, E> Eq for LiftedFunction<V, E>
where
E: Evaluator<Space = V>,
V: Clone + PartialEq + Send + Sync,
{
}
pub struct LiftedLazyFunction<V: Clone + PartialEq + Send + Sync, E: LazyEvaluator<Space = V>>(
Arc<ReducedExpression<V>>,
Arc<E>,
Arc<VecDeque<ReducedExpression<V>>>,
);
impl<V, E> LiftedLazyFunction<V, E>
where
E: LazyEvaluator<Space = V>,
V: Clone + PartialEq + Send + Sync,
{
pub fn eval(&self, xs: &[V]) -> Result<V, E::Error> {
self.0.lazy_eval_inps_with_env(&self.1, &self.2, xs)
}
}
impl<V, E> Clone for LiftedLazyFunction<V, E>
where
E: LazyEvaluator<Space = V>,
V: Clone + PartialEq + Send + Sync,
{
fn clone(&self) -> Self {
LiftedLazyFunction(self.0.clone(), self.1.clone(), self.2.clone())
}
}
impl<V, E> PartialEq for LiftedLazyFunction<V, E>
where
E: LazyEvaluator<Space = V>,
V: Clone + PartialEq + Send + Sync,
{
fn eq(&self, other: &LiftedLazyFunction<V, E>) -> bool {
self.0 == other.0 && self.2 == other.2
}
}
impl<V, E> Eq for LiftedLazyFunction<V, E>
where
E: LazyEvaluator<Space = V>,
V: Clone + PartialEq + Send + Sync,
{
}
use self::ReducedExpression::*;
#[derive(Clone, PartialEq)]
pub enum ReducedExpression<V: Clone + PartialEq + Send + Sync> {
Value(V),
Primitive(String, TypeSchema),
Application(Vec<ReducedExpression<V>>),
Abstraction(usize, Box<ReducedExpression<V>>),
Index(usize),
}
impl<V> fmt::Debug for ReducedExpression<V>
where
V: Clone + PartialEq + Send + Sync,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Value(_) => write!(f, "Value"),
Primitive(ref s, _) => write!(f, "Primitive({})", s),
Application(ref xs) => write!(f, "Application({:?})", xs),
Abstraction(depth, ref body) => write!(f, "Abstraction({}, {:?})", depth, body),
Index(n) => write!(f, "Index({})", n),
}
}
}
impl<V> ReducedExpression<V>
where
V: Clone + PartialEq + Send + Sync,
{
pub fn new(dsl: &Language, expr: &Expression) -> Self {
Self::from_expr(dsl, &dsl.strip_invented(expr))
}
pub fn eval_inps_with_env<E>(
&self,
evaluator: &Arc<E>,
env: &Arc<VecDeque<ReducedExpression<V>>>,
inps: &[V],
) -> Result<V, E::Error>
where
E: Evaluator<Space = V>,
{
let expr = self.clone().with_args(inps);
let mut evaluated = expr.eval(evaluator, env)?;
loop {
let next = evaluated.eval(evaluator, env)?;
if next == evaluated {
break;
}
evaluated = next;
}
match evaluated {
Value(o) => Ok(o),
e => panic!("tried to evaluate an irreducible expression: {:?}", e),
}
}
pub fn lazy_eval_inps_with_env<E>(
&self,
evaluator: &Arc<E>,
env: &Arc<VecDeque<ReducedExpression<V>>>,
inps: &[V],
) -> Result<V, E::Error>
where
E: LazyEvaluator<Space = V>,
{
let expr = self.clone().with_args(inps);
let mut evaluated = expr.lazy_eval(evaluator, env)?;
loop {
let next = evaluated.lazy_eval(evaluator, env)?;
if next == evaluated {
break;
}
evaluated = next;
}
match evaluated {
Value(o) => Ok(o),
e => panic!("tried to evaluate an irreducible expression {:?}", e),
}
}
pub fn eval_inps<E>(&self, evaluator: &Arc<E>, inps: &[V]) -> Result<V, E::Error>
where
E: Evaluator<Space = V>,
{
let env = Arc::new(VecDeque::new());
self.eval_inps_with_env(evaluator, &env, inps)
}
pub fn lazy_eval_inps<E>(&self, evaluator: &Arc<E>, inps: &[V]) -> Result<V, E::Error>
where
E: LazyEvaluator<Space = V>,
{
let env = Arc::new(VecDeque::new());
self.lazy_eval_inps_with_env(evaluator, &env, inps)
}
fn eval<E>(
&self,
evaluator: &Arc<E>,
env: &Arc<VecDeque<ReducedExpression<V>>>,
) -> Result<ReducedExpression<V>, E::Error>
where
E: Evaluator<Space = V>,
{
match *self {
Application(ref xs) => {
let f = &xs[0];
let mut xs: Vec<_> = xs[1..]
.iter()
.map(|x| x.eval(evaluator, env))
.collect::<Result<_, _>>()?;
match *f {
Primitive(ref name, ref tp) => {
let arity = arity(tp);
if arity == 0 {
panic!(
"tried to apply a primitive that wasn't a function: {}",
name
)
} else if xs.len() < arity
|| !xs.iter().take(arity).all(|x| match *x {
Value(_) | Abstraction(_, _) => true, _ => false,
})
{
xs.insert(0, f.eval(evaluator, env)?);
Ok(Application(xs))
} else {
let mut args = xs;
let mut xs = args.split_off(arity);
let args: Vec<V> = args
.into_iter()
.map(|x| match x {
Value(v) => v,
Abstraction(_, _) => {
let env = env.clone();
evaluator
.clone()
.lift(LiftedFunction(
Arc::new(x),
evaluator.clone(),
env.clone(),
))
.expect("evaluator could not lift an abstraction")
}
_ => unreachable!(),
})
.collect();
let v = Value(evaluator.evaluate(name, &args)?);
if xs.is_empty() {
Ok(v)
} else {
xs.insert(0, v);
Ok(Application(xs))
}
}
}
Abstraction(ref depth, ref body) => {
if xs.is_empty() {
Ok(Abstraction(*depth, body.clone()))
} else {
let mut env = (**env).clone();
let mut depth: usize = *depth;
xs.reverse();
while !xs.is_empty() && depth > 0 {
let binding = xs.pop().unwrap();
env.push_front(binding);
depth -= 1;
}
xs.reverse();
let v = body.eval(evaluator, &Arc::new(env))?;
if depth > 0 {
Ok(Abstraction(depth, Box::new(v)))
} else if xs.is_empty() {
Ok(v)
} else if let Application(mut v) = v {
v.extend(xs);
Ok(Application(v))
} else {
xs.insert(0, v);
Ok(Application(xs))
}
}
}
_ => {
xs.insert(0, f.eval(evaluator, env)?);
Ok(Application(xs))
}
}
}
Primitive(ref name, ref tp) => {
if is_arrow(tp) {
Ok(Primitive(name.clone(), tp.clone()))
} else {
Ok(Value(evaluator.evaluate(name, &[])?))
}
}
Index(i) => match env.get(i) {
Some(x) => Ok(x.clone()),
None => Ok(Index(i)),
},
_ => Ok(self.clone()),
}
}
fn lazy_eval<E>(
&self,
evaluator: &Arc<E>,
env: &Arc<VecDeque<ReducedExpression<V>>>,
) -> Result<ReducedExpression<V>, E::Error>
where
E: LazyEvaluator<Space = V>,
{
match *self {
Application(ref exprs) => {
let f = &exprs[0];
let xs = &exprs[1..];
match *f {
Primitive(ref name, ref tp) => {
let arity = arity(tp);
if arity == 0 {
panic!(
"tried to apply a primitive that wasn't a function: {}",
name
)
} else if xs.len() < arity {
Ok(Application(exprs.clone()))
} else {
let mut args: Vec<_> = xs.to_vec();
let mut xs = args.split_off(arity);
let args: Vec<_> = args
.into_iter()
.map(|x| {
if let Abstraction(_, _) = x {
Value(
evaluator
.clone()
.lift(LiftedLazyFunction(
Arc::new(x),
evaluator.clone(),
env.clone(),
))
.expect("evaluator could not lift an abstraction"),
)
} else {
x
}
})
.map(|x| {
LiftedLazyFunction(Arc::new(x), evaluator.clone(), env.clone())
})
.collect();
let v = Value(evaluator.lazy_evaluate(name, &args)?);
if xs.is_empty() {
Ok(v)
} else {
xs.insert(0, v);
Ok(Application(xs))
}
}
}
Abstraction(ref depth, ref body) => {
if xs.is_empty() {
Ok(Abstraction(*depth, body.clone()))
} else {
let mut env = (**env).clone();
let mut depth: usize = *depth;
let mut xs: Vec<_> = xs.iter().rev().cloned().collect();
while !xs.is_empty() && depth > 0 {
let binding = xs.pop().unwrap();
env.push_front(binding);
depth -= 1;
}
xs.reverse();
let env = Arc::new(env);
let mut body = (*body).clone();
body.substitute_indices(&env, 0);
let v = body.lazy_eval(evaluator, &env)?;
if depth > 0 {
Ok(Abstraction(depth, Box::new(v)))
} else if xs.is_empty() {
Ok(v)
} else if let Application(mut v) = v {
v.extend(xs);
Ok(Application(v))
} else {
Ok(Application(exprs.clone()))
}
}
}
_ => Ok(Application(exprs.clone())),
}
}
Primitive(ref name, ref tp) => {
if is_arrow(tp) {
Ok(Primitive(name.clone(), tp.clone()))
} else {
Ok(Value(evaluator.lazy_evaluate(name, &[])?))
}
}
Index(i) => match env.get(i) {
Some(x) => Ok(x.clone()),
None => Ok(Index(i)),
},
_ => Ok(self.clone()),
}
}
fn with_args(self, inps: &[V]) -> Self {
if inps.is_empty() {
self
} else {
let mut inps: Vec<_> = inps.iter().map(|v| Value(v.clone())).collect();
match self {
Application(mut xs) => {
xs.extend(inps);
Application(xs)
}
_ => {
inps.insert(0, self);
Application(inps)
}
}
}
}
fn from_expr(dsl: &Language, expr: &Expression) -> Self {
match *expr {
Expression::Primitive(num) => {
Primitive(dsl.primitives[num].0.clone(), dsl.primitives[num].1.clone())
}
Expression::Application(ref f, ref x) => {
let mut v = vec![Self::from_expr(dsl, x)];
let mut f: &Expression = f;
while let Expression::Application(ref inner_f, ref x) = *f {
v.push(Self::from_expr(dsl, x));
f = inner_f;
}
v.push(Self::from_expr(dsl, f));
v.reverse();
Application(v)
}
Expression::Abstraction(ref body) => {
let mut body: &Expression = body;
let mut depth = 1;
while let Expression::Abstraction(ref inner_body) = *body {
depth += 1;
body = inner_body;
}
Abstraction(depth, Box::new(Self::from_expr(dsl, body)))
}
Expression::Index(i) => Index(i),
Expression::Invented(_) => unreachable!(), }
}
fn substitute_indices(&mut self, env: &Arc<VecDeque<ReducedExpression<V>>>, offset: usize) {
match *self {
Application(ref mut xs) => {
for x in xs {
x.substitute_indices(env, offset)
}
}
Abstraction(depth, ref mut body) => body.substitute_indices(env, offset + depth),
Index(i) if i >= offset => {
if let Some(x) = env.get(i - offset) {
*self = x.clone()
}
}
_ => (),
}
}
}
fn arity(mut tp: &TypeSchema) -> usize {
let mut tp = loop {
match *tp {
TypeSchema::Monotype(ref t) => break t,
TypeSchema::Polytype { ref body, .. } => tp = body,
}
};
let mut count = 0;
while let Some((_, ret)) = tp.as_arrow() {
count += 1;
tp = ret;
}
count
}
fn is_arrow(mut tp: &TypeSchema) -> bool {
loop {
match *tp {
TypeSchema::Monotype(ref t) => break t.as_arrow().is_some(),
TypeSchema::Polytype { ref body, .. } => tp = body,
}
}
}