Struct programinduction::lambda::LispEvaluator
[−]
[src]
pub struct LispEvaluator { /* fields omitted */ }Execute expressions in a simple lisp interpreter.
Cannot handle:
- define/let
- quote/quasiquote
- (escaped) double quotes in a string literal
- rational and complex numbers
- some obviously sophisticated things (e.g. continuations)
If you want a more sophisticated lisp interpreter, you can install racket and enable the racket feature which will spawn threads for evaluating expressions with the racket REPL.
[dependencies.programinduction]
version = "0.1"
features = ["racket"]
Examples
#[macro_use] extern crate polytype; extern crate programinduction; use programinduction::lambda::{Language, LispEvaluator}; let dsl = Language::uniform(vec![ ("map", arrow![arrow![tp!(0), tp!(1)], tp!(list(tp!(0))), tp!(list(tp!(1)))]), ("*2", arrow![tp!(int), tp!(int)]), ("+", arrow![tp!(int), tp!(int), tp!(int)]), ("1", tp!(int)), ]); let lisp = LispEvaluator::new(vec![ // only one primitive in our DSL doesn't match what's provided by the interpreter: ("*2", "(λ (x) (* x 2))"), ]); let task = lisp.make_task( arrow![tp!(list(tp!(int))), tp!(list(tp!(int)))], &[ // these are evaluated along with the expression. ("(list 1 2 3)", "(list 2 4 6)"), ("(list 3 5)", "(list 6 10)"), ], ); // this expression fails the task let expr = dsl.parse("(λ (map (λ (+ 1 $0)) $0))").expect("parse"); assert!((task.oracle)(&dsl, &expr).is_infinite()); // this expression succeeds let expr = dsl.parse("(λ (map *2 $0))").expect("parse"); assert!((task.oracle)(&dsl, &expr).is_finite());
Methods
impl LispEvaluator[src]
pub fn new(prims: Vec<(&str, &str)>) -> Self[src]
Create a lisp evaluator.
Primitives used in an expression are automatically treated as arbitrary symbols by the interpreter. So make sure any primitives you need that either are not in scheme or have different type than in scheme are specified.
Examples
use programinduction::lambda; let lisp = lambda::LispEvaluator::new(vec![ ("+1", "(lambda (x) (+ 1 x))"), ("*2", "(λ (x) (* 2 x))"), ]);
pub fn check(
&self,
dsl: &Language,
expr: &Expression,
input: Option<&str>,
output: &str
) -> Result<bool, LispError>[src]
&self,
dsl: &Language,
expr: &Expression,
input: Option<&str>,
output: &str
) -> Result<bool, LispError>
Check if an expressions matches expected output by evaluating it.
If input is None, the expression is treated as a constant and compared to the output.
Otherwise, the expression is treated as a unary procedure and is applied to the input
before comparison to the output.
Examples
let dsl = Language::uniform(vec![ ("+", arrow![tp!(int), tp!(int), tp!(int)]), ("1", tp!(int)), ("2", tp!(int)), ]); let lisp = LispEvaluator::default(); // 2 + 2 == 4 let expr = dsl.parse("(+ 2 2)").expect("parse"); assert!(lisp.check(&dsl, &expr, None, "4").unwrap()); // 1 + 2 != 4 let expr = dsl.parse("(+ 1 2)").expect("parse"); assert!(!lisp.check(&dsl, &expr, None, "4").unwrap());
pub fn check_many(
&self,
dsl: &Language,
expr: &Expression,
examples: &[(&str, &str)]
) -> Result<bool, LispError>[src]
&self,
dsl: &Language,
expr: &Expression,
examples: &[(&str, &str)]
) -> Result<bool, LispError>
Like check, but checks against multiple input/output pairs.
Expressions is treated as unary procedures and are applied to each input before comparison to the corresponding output.
Examples
let dsl = Language::uniform(vec![ ("map", arrow![arrow![tp!(0), tp!(1)], tp!(list(tp!(0))), tp!(list(tp!(1)))]), ("list", arrow![tp!(int), tp!(int), tp!(list(tp!(int)))]), ("*2", arrow![tp!(int), tp!(int)]), ("+", arrow![tp!(int), tp!(int), tp!(int)]), ("1", tp!(int)), ("2", tp!(int)), ]); let lisp = LispEvaluator::new(vec![ // only one primitive in our DSL doesn't match what's provided by the interpreter: ("*2", "(λ (x) (* x 2))"), ]); let expr = dsl.parse("(λ (map (λ (+ (*2 1) $0)) $0))").expect("parse"); assert!( lisp.check_many(&dsl, &expr, &[("(list 1 2)", "(list 3 4)")]) .expect("evaluation should not fail") );
pub fn make_task<'a>(
&'a self,
tp: Type,
examples: &[(&'a str, &'a str)]
) -> Task<'a, Language, Expression, Vec<(String, String)>>[src]
&'a self,
tp: Type,
examples: &[(&'a str, &'a str)]
) -> Task<'a, Language, Expression, Vec<(String, String)>>
Create a task based on evaluating a lisp expressions against test input/output pairs.
The resulting task is "all-or-nothing": the oracle returns either 0 if all examples are
correctly hit or f64::NEG_INFINITY otherwise.
pub fn make_task_output_only<'a>(
&'a self,
tp: Type,
output: &'a str
) -> Task<'a, Language, Expression, String>[src]
&'a self,
tp: Type,
output: &'a str
) -> Task<'a, Language, Expression, String>
Like make_task, but doesn't treat expressions as unary procedures: they are evaluated
and directly compared against the output.