This is definitely true, but you can often get surprisingly far by just boxing, cloning, Rc-ing, etc. whenever you hit something like this.
from memory:
trait Prop<'a, T> {
fn p<F: Fn(&'a T) -> bool>(f: F) -> Self;
fn eval(&self, &'a T) -> bool;
}
enum LiftedBool<'a, T, F: Fn(&'a T) -> bool> {
Base(Box<F>),
And(LiftedBool<'a, T, F>, LiftedBool<'a, T, F>),
Or(LiftedBool<'a, T, F>, LiftedBool<'a, T, F>),
Not(LiftedBool<'a, T, F>),
}
impl<'a, T, F: Fn(&'a T) -> bool> Prop<'a, T> for LiftedBool<'a, T, F> {
fn p<F: Fn(&'a T) -> bool>(f: F) -> Self {
// this fails because `F` in the impl doesn't necessarily unify with `F` in the trait definition
// it can be made to work with `dyn` for the function argument but requires boilerplate to actually use
}
fn eval(&self, &'a T) -> bool {
// obvious evaluation by cases
}
}
this example can be fixed to work via `dyn` for the argument on the trait function and the struct itself but it becomes increasingly painful to actually work with. this kind of generic work is not at all ergonomic but very easy in Haskell.