-
Notifications
You must be signed in to change notification settings - Fork 4
Description
I've been trying to create a resolver for arithmetics and I found the interface of the trait to be somewhat confusing.
Here's the trait for reference:
pub trait Resolver {
type Choice: fmt::Debug;
fn resolve(
&mut self,
goal_id: term_arena::TermId,
goal_term: term_arena::AppTerm,
context: &mut ResolveContext,
) -> Option<Resolved<Self::Choice>>;
/// Returns true if there's another resolution pending.
fn resume(
&mut self,
choice: &mut Self::Choice,
goal_id: term_arena::TermId,
context: &mut ResolveContext,
) -> bool;
}
As far as I undestand it, the resolver exists to return a chain of results. Every result can either just match, which means "the statement is true", or instantiate a variable to some concrete value, and let the resolution process continue elsewhere. The first lack of match breaks the chain.
Did I get that right?
If yes, then Resolver::Choice reminds me of an Iterator a lot. Without getting into how all this works, I'd imagine returning an Iterator that yields which variable should take which value or stop, something along the lines of:
enum Choice {
Substitute(Var, Term),
Match,
}
pub trait Resolver {
fn resolve(
&mut self,
goal_id: term_arena::TermId,
goal_term: term_arena::AppTerm,
context: &mut ResolveContext,
) -> impl Iterator<Item=Choice>;
}
If that doesn't make sense, I'm seeing a couple of less invasive rough edges with this API.
One simple thing is that ::resume returns a bool where it could return another choice:
/// Returning None means nothing more can be resolved.
fn resume(
&mut self,
choice: Self::Choice,
goal_id: term_arena::TermId,
context: &mut ResolveContext,
) -> Option<Self::Choice>;
Another thing is that Resolver::resolve duplicates ::resume when it returns the first result (e.g. in RuleResolver). I think this could be avoided by calling ::resume first thing after each ::resolve.
When I tried it, it becomes clear that while the normal place to fail and stop resolution is ::resume, sometimes ::resolve already wants to fail immediately, so that would lead to some weird overlap of function.
I decided not to make a pull request from what I have without confirming that it's even desireable.
This all ultimately comes from the need to have a CLP/FD approximation :P Scryer Prolog has some downsides compared to Logru.