Skip to content

Commit

Permalink
Merge pull request #271 from vsbogd/consume-errors-in-superpose
Browse files Browse the repository at this point in the history
Fix superpose to interpret arguments independently
  • Loading branch information
vsbogd authored Apr 10, 2023
2 parents 10758f5 + 46b350d commit 8a58ba4
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 13 deletions.
89 changes: 77 additions & 12 deletions lib/src/metta/runner/stdlib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -612,7 +612,15 @@ impl Grounded for CollapseOp {
}

#[derive(Clone, PartialEq, Debug)]
pub struct SuperposeOp { }
pub struct SuperposeOp {
space: Shared<GroundingSpace>,
}

impl SuperposeOp {
fn new(space: Shared<GroundingSpace>) -> Self {
Self{ space }
}
}

impl Display for SuperposeOp {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Expand All @@ -622,16 +630,22 @@ impl Display for SuperposeOp {

impl Grounded for SuperposeOp {
fn type_(&self) -> Atom {
Atom::expr([ARROW_SYMBOL, ATOM_TYPE_UNDEFINED, ATOM_TYPE_UNDEFINED])
Atom::expr([ARROW_SYMBOL, ATOM_TYPE_EXPRESSION, ATOM_TYPE_UNDEFINED])
}

fn execute(&self, args: &mut Vec<Atom>) -> Result<Vec<Atom>, ExecError> {
let arg_error = || ExecError::from("superpose expects single expression as an argument");
// `superpose` receives one atom (expression) in order to make composition
// `(superpose (collapse ...))` possible
let expr = atom_as_expr(args.get(0).ok_or_else(arg_error)?).ok_or(arg_error())?;
let atom = args.get(0).ok_or_else(arg_error)?;
let expr = atom_as_expr(&atom).ok_or(arg_error())?;

Ok(expr.children().clone())
let mut superposed = Vec::new();
for atom in expr.children() {
match interpret_no_error(self.space.clone(), atom) {
Ok(results) => { superposed.extend(results); },
Err(message) => { return Err(format!("Error: {}", message).into()) },
}
}
Ok(superposed)
}

fn match_(&self, other: &Atom) -> MatchResultIter {
Expand Down Expand Up @@ -1069,8 +1083,6 @@ pub fn register_common_tokens(metta: &Metta) {
tref.register_token(regex(r"cdr-atom"), move |_| { cdr_atom_op.clone() });
let cons_atom_op = Atom::gnd(ConsAtomOp{});
tref.register_token(regex(r"cons-atom"), move |_| { cons_atom_op.clone() });
let superpose_op = Atom::gnd(SuperposeOp{});
tref.register_token(regex(r"superpose"), move |_| { superpose_op.clone() });
let println_op = Atom::gnd(PrintlnOp{});
tref.register_token(regex(r"println!"), move |_| { println_op.clone() });
let trace_op = Atom::gnd(TraceOp{});
Expand Down Expand Up @@ -1103,6 +1115,8 @@ pub fn register_runner_tokens(metta: &Metta, cwd: PathBuf) {
tref.register_token(regex(r"assertEqualToResult"), move |_| { assert_equal_to_result_op.clone() });
let collapse_op = Atom::gnd(CollapseOp::new(space.clone()));
tref.register_token(regex(r"collapse"), move |_| { collapse_op.clone() });
let superpose_op = Atom::gnd(SuperposeOp::new(space.clone()));
tref.register_token(regex(r"superpose"), move |_| { superpose_op.clone() });
let get_type_op = Atom::gnd(GetTypeOp::new(space.clone()));
tref.register_token(regex(r"get-type"), move |_| { get_type_op.clone() });
// TODO: here clone of the metta is moved into separate location in memory.
Expand Down Expand Up @@ -1157,12 +1171,14 @@ pub fn metta_code() -> &'static str {
(: if (-> Bool Atom Atom $t))
(= (if True $then $else) $then)
(= (if False $then $else) $else)
(: Error (-> Atom Atom ErrorType))
"
}

#[cfg(test)]
mod tests {
use super::*;
use crate::metta::runner::*;
use crate::metta::types::validate_atom;

#[test]
Expand Down Expand Up @@ -1352,19 +1368,68 @@ mod tests {

#[test]
fn superpose_op() {
let superpose_op = SuperposeOp{};
let space = Shared::new(GroundingSpace::new());
let superpose_op = SuperposeOp::new(space);
assert_eq!(superpose_op.execute(&mut vec![expr!("A" ("B" "C"))]),
Ok(vec![sym!("A"), expr!("B" "C")]));
}

#[test]
fn superpose_op_type() {
let space = GroundingSpace::new();
assert!(validate_atom(&space, &expr!({SumOp{}}
({SuperposeOp{}} ({Number::Integer(1)} {Number::Integer(2)} {Number::Integer(3)}))
let space = Shared::new(GroundingSpace::new());
assert!(validate_atom(space.borrow().deref(), &expr!({SumOp{}}
({SuperposeOp::new(space.clone())} ({Number::Integer(1)} {Number::Integer(2)} {Number::Integer(3)}))
{Number::Integer(1)})));
}

#[test]
fn superpose_op_multiple_interpretations() {
let metta = new_metta_rust();
let mut parser = SExprParser::new("
(= (f) A)
(= (f) B)
(= (g) C)
(= (g) D)
!(superpose ((f) (g)))
");

assert_eq_metta_results!(metta.run(&mut parser),
Ok(vec![vec![expr!("A"), expr!("B"), expr!("C"), expr!("D")]]));
}

#[test]
fn superpose_op_superposed_with_collapse() {
let metta = new_metta_rust();
let mut parser = SExprParser::new("
(= (f) A)
(= (f) B)
!(let $x (collapse (f)) (superpose $x))
");

assert_eq_metta_results!(metta.run(&mut parser),
Ok(vec![vec![expr!("A"), expr!("B")]]));
}

#[test]
fn superpose_op_consumes_interpreter_errors() {
let metta = new_metta_rust();
let mut parser = SExprParser::new("
(: f (-> A B))
(= (f $x) $x)
(: a A)
(: b B)
!(superpose ((f (nop)) (f a) (f b)))
");

assert_eq!(metta.run(&mut parser), Ok(vec![vec![
expr!("Error" ("f" ({NopOp{}})) "NoValidAlternatives"),
expr!("a"), expr!("Error" "b" "BadType")]]));
}

#[test]
fn get_type_op() {
let space = Shared::new(metta_space("
Expand Down
2 changes: 1 addition & 1 deletion python/tests/scripts/b4_nondeterm.metta
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
; `superpose` reverts `collapse`
!(assertEqual
(color)
(superpose (collapse (color))))
(let $x (collapse (color)) (superpose $x)))

; In contrast to `match`, if the equality query returns an empty result
; the interpreter doesn't reduce a symbolic expression
Expand Down

0 comments on commit 8a58ba4

Please sign in to comment.