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?