I am working on translating a simple prolog implementation in Haskell to Rust for fun, and to get some more experience using the language.
In Haskell, I have a type class:
class Unifiable t v | t -> v where
variables :: t -> [v]
subs :: Unifier v t -> t -> t
unify :: t -> t -> (Maybe (Unifier v t))
Which I translated into the following trait in Rust:
pub type Unifier<V,T> = HashMap<V,T>;
pub trait Unifiable<T,V> {
fn variables(term: T) -> Vec<V>;
fn subs(unifier: Unifier<V,T>, term: T) -> T;
fn unify(firstTerm: T, secondTerm: T) -> Option<Unifier<V,T>>;
I then have the definition of a utility function that I would like to be able to use whenever an instance of Unifiable is available. As a preliminary definition, I used this:
pub fn compose<V: Hash + Eq, T, U: Unifiable<T,V>>(first: Unifier<V,T>, other: Unifier<V,T>) -> Unifier<V,T> {
let unifier: Unifier<V,T> = first.iter().map(|(&x,y)| (x, U::subs(other, *y))).collect();
unifier.extend(other);
return unifier;
}
which I am intending on being analogous to the Haskell type signature:
compose :: Unifiable v t => Unifier v t -> Unifier v t -> Unifier v t
The problem is, I would like to use this helper function compose in an impl block for Unifiable, and I am not sure how to refer to to the Unifiable instance at the call site:
impl <T: Eq, V: Clone + Eq + Hash> Unifiable<Term<T,V>,V> for Term<T,V> {
...
fn unify(firstTerm: Term<T,V>, secondTerm: Term<T,V>) -> Option<Unifier<V,Term<T,V>>> {
....
return Some(compose<V,Term<T,V>,X>(u, us));
....
}
...
}
The issue being, I don't know what to use for X to refer to the Unifiable instance in the impl block I'm currently defining, and if I leave out the type parameters, I get a "cannot infer type parameter" error. Is this sort of reference with traits possible in Rust?
uandus? It would help if you gave an example with working code (except for the type error, that is) that we could run in the Rust Playground. - Aplet123