Yes, generics are infectious. Just like regular functions. Most use of generics are just type-level functions anyway, so there's that. If your type depends on a type parameter, you have to somehow supply that parameter. Either by assigning a concrete type to it, or by passing the requirement (and the decision) up the chain to someone who will eventually be able to supply a concrete type. Similarly, if your function depends on a value passed in as an argument, then any callers of that function will either pass a specific value to it, or they need to delegate that responsibility by including a corresponding argument themselves.
Of course, one "trick" is to replace the parameter with a technically concrete type without being too concrete. That's what trait objects are for. So, instead of making your
State generic over
F, you could just store a
Box<dyn Fn()> in it (or better yet, a
Box<dyn FnMut()> in order to allow more kinds of callbacks). This makes the type parameter go away, because
dyn FnMut() is a concrete type – even though you can still construct the same trait object from many different underlying concrete types. It will, however, incur the (minor) additional cost of dynamic dispatch on your code.