Struct TextualUniverse
pub struct TextualUniverse {
pub symbols: SymbolStore,
pub rules: RuleSet,
}
Expand description
A universe that can be interacted with using a Prolog like syntax.
It builds on the [SymbolStore
] and [RuleSet
] abstractions and additionally provides a
fully textual syntax for defining rules and queries, looking very similar to Prolog.
Syntactic elements:
- Variables: An identifier starting with a upper case ASCII latter followed by zero or more
ASCII letters, digits or underscores, e.g.
X
,Person
,FooBar
. - Symbols: An identifier starting with a lower case ASCII latter followed by zero or more
ASCII letters, digits or underscores, e.g.
foo
,rightOf
,is_natural
. - Application Terms: An application of a functor to arguments, e.g.
is_natural(X)
oradd(X, z, Y)
. - Facts: An application term followed by a dot, e.g.
is_natural(z).
. - Rules: An application term followed by
:-
(a reverse implication arrow) and a comma separated list of one or more conjunctive conditions, followed by a dot, e.g.grandparent(A, B) :- parent(A, C), parent(C, B).
. - Queries: A comma separated list of one or more conjunctive conditions, followed by a dot,
e.g.
grandparent(bob, A), female(A).
.
It doesn’t support comments and the moment, so that is probably a good idea for the future.
Besides functions for parsing, the textual universe also provides pretty-printing facilities.
§Example
Definitions of facts and rules can be loaded from a string that contains zero or more facts or rules as described above. In the following example, we define a set of Peano arithmetic rules and compute the first 5 square numbers.
let mut u = TextualUniverse::new();
u.load_str(
r#"
is_natural(z).
is_natural(s(A)) :- is_natural(A).
add(A, z, A) :- is_natural(A).
add(A, s(B), s(C)) :- add(A, B, C).
mul(A, z, z) :- is_natural(A).
mul(A, s(B), C) :- mul(A, B, D), add(A, D, C).
"#,
)
.unwrap();
let query = u.prepare_query("mul(X,X,Y).").unwrap();
let solutions = query_dfs(u.resolver(), query.query());
for solution in solutions.take(5) {
println!("SOLUTION:");
for (var, term) in solution.iter_vars() {
if let Some(term) = term {
println!(" ${} = {}", var.ord(), query.pretty().term_to_string(&term));
} else {
println!("<bug: no solution>");
}
}
}
Fields§
§symbols: SymbolStore
§rules: RuleSet
Implementations§
§impl TextualUniverse
impl TextualUniverse
pub fn new() -> TextualUniverse
pub fn prepare_query(
&self,
query: &str,
) -> Result<UniverseQuery<'_>, ParseError>
pub fn prepare_query( &self, query: &str, ) -> Result<UniverseQuery<'_>, ParseError>
Parse a query, but do not run it.
pub fn query_dfs(
&mut self,
query: &str,
) -> Result<SolutionIter<RuleResolver<'_>>, ParseError>
pub fn query_dfs( &mut self, query: &str, ) -> Result<SolutionIter<RuleResolver<'_>>, ParseError>
Run a query against the universe using the DFS solver.
§Notes
When you need access to the pretty printer while the solution iterator is still live, use
Self::prepare_query
instead. This method needs to take a mutable reference of the
universe because parsing can discover new symbols that need to be added to the universe
before running the query. Running a query by itself only requires a shared reference, and
thus the pretty-printer is still accessible.
pub fn pretty(&self) -> Prettifier<'_, SymbolStore>
pub fn pretty(&self) -> Prettifier<'_, SymbolStore>
Return a pretty-printer using the symbols defined in this universe.
pub fn parse(&mut self) -> Parser<&mut SymbolStore>
pub fn parse(&mut self) -> Parser<&mut SymbolStore>
Return a term parser that uses the name mapping of this universe for parsing terms.
pub fn resolver(&self) -> RuleResolver<'_>
pub fn resolver(&self) -> RuleResolver<'_>
Return a resolver for the internal rule database.