Why does trait inference fail here?

pub trait P<A>                      
{                                   
    fn p(a: A) -> Option<A>;        
}                                   
impl P<Self> for &str {             
    fn p(a: Self) -> Option<Self>   
    {                               
        Some(a)                     
    }                               
}                                   
fn main() {                         
    let a: &str = "what";
    let _: Option<&str> = <&str>::p(a);
    let _: Option<&str> = <_>::p(a); // <-- this is an inference error
}

Link to the playground: Rust Playground

Shouldn't it be able to see which impl to use from the explicit input and output types?

I think it's good that it fails here, because it'd be ambiguous if any other type implemented P<&str> -- which they're free to do.

Could you elaborate on why this needs A, vs just being

pub trait P                    
{                                   
    fn p(a: Self) -> Option<Self>;        
}  

I was playing with RustyYato's typefamilies: GitHub - RustyYato/type-families

But taking my own sort of approach to some parts of the design and I noticed it was hard to get the type inference to workout in the do-notation and I tracked it down to this minimal example of the issue. It's a little bit weird to me coming from a Haskell background because the equivalent Haskell program type checks just fine:

class P a where
  p :: a -> Maybe a
instance P [a] where
  p = Just

main = do
  print (p "what")

(You might object and say they are slightly different programs, but I can also change the instance to [Char] and I only need to enable FlexibleInstances which is a pretty conservative extension and then it type checks again.)

If I need to put Self in the signature of p then it's back to the drawing board I guess.

Oh right, so pub trait P<a> actually has one more free variable than the Haskell version. That's kind of goofing up my translation here.

This appears to be what I was after:

pub trait TyImp {
    type Imp;
}
pub trait P: TyImp
{
    fn p(a: Self::Imp) -> Self;
}

impl<A> TyImp for Option<A> {
    type Imp=A;
}
impl<A> P for Option<A> {
    fn p(a: A) -> Option<A>
    {
        Some(a)
    }
}

Yeah, exactly.

The reason you'd want a trait like that is some kind of a compile-time strategy pattern. So you could do TypeParam::p(a). But that's the kind of place where you don't want <_>::p(a) picking Foo::p or Bar::p.

Yep, this exactly. You'll need that self parameter to mske inference work out nicely. Note: you co up ld require that the type family implements Default and Copy to mske it easier to work with.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.