pub fn task_by_evaluation<E, V>(
    evaluator: E,
    tp: TypeScheme,
    examples: impl AsRef<[(Vec<V>, V)]> + Sync
) -> impl Task<[(Vec<V>, V)], Representation = Language, Expression = Expression>
where E: Evaluator<Space = V> + Send, V: PartialEq + Clone + Send + Sync,
Expand description

Create a task based on evaluating lambda calculus expressions on test input/output pairs.

Here we let all tasks be represented by input/output pairs that are values in the space of type V. For example, circuits may have V be just bool, whereas string editing may have V be an enum featuring strings, chars, and natural numbers. All inputs, outputs, and evaluated expressions must be representable by V.

An evaluator takes the name of a primitive and a vector of sequential inputs to the expression (so an expression with unary type will have one input in a vec of size 1).

The resulting task is “all-or-nothing”: the oracle returns either 0 if all examples are correctly hit or f64::NEG_INFINITY otherwise.

Examples

use polytype::{ptp, tp};
use programinduction::{Task, lambda::{task_by_evaluation, Language, SimpleEvaluator}};

fn evaluate(name: &str, inps: &[i32]) -> Result<i32, ()> {
    match name {
        "0" => Ok(0),
        "1" => Ok(1),
        "+" => Ok(inps[0] + inps[1]),
        _ => unreachable!(),
    }
}

let examples = vec![(vec![2, 5], 8), (vec![1, 2], 4)];
let tp = ptp!(@arrow[tp!(int), tp!(int), tp!(int)]);
let task = task_by_evaluation(SimpleEvaluator::from(evaluate), tp, &examples);

let dsl = Language::uniform(vec![
    ("0", ptp!(int)),
    ("1", ptp!(int)),
    ("+", ptp!(@arrow[tp!(int), tp!(int), tp!(int)])),
]);
let expr = dsl.parse("(λ (+ (+ 1 $0)))").unwrap();
assert!(task.oracle(&dsl, &expr).is_finite())