I understand that in Rust, all (and only) lambda expressions are closures; and closures are trait types such as Fn
.
I understand we can emulate rank-2 (higher ranked) types in a language which doesn't explicitly support them via forall
, by employing a trait with a method for generic parameter A
, as explained in an example for Scala.
Compared to that linked Scala example, the example in this thread is not requiring a higher ranked type, because the Read
trait lower bound is constant throughout the function f
. Also afaics, the example in this thread does not require a higher-kinded type on the trait Fn
in order to parameterize the lower bound on the type parameter A
of Fn
, i.e. requires a trait Fn<A>
to be of the type trait Fn<Read>
. Higher-kinded types are of the form trait HK<A, B<A>>
.
Agreed. The reason the example of this thread won't compile is not due to a lack of higher-kinded nor higher-ranked types, but rather because afaik the way Rust implements ad hoc polymorphism is it creates a separate instance of each function for each caller that uses a different set of input types, i.e. Rust's implementation is not a dynamic dispatch of passing in a hidden input argument for the dictionary for the trait implementation of the caller and is instead hard-coding the dictionary in each instance of the function, e.g. is not subclassing nor dynamic inversion-of-control ad hoc polymorphism (where the caller inputs the dictionary). Thus the function f
has no way to control the types of Read
instance of G
it wants unless it specifies them. If f
knows all the specific instance of Read
it will use, then it can specify them as the lower bound on A
instead of Read
, except there is the problem that Rust (nor Haskell, nor Scala, nor Kotlin, etc) does not support first-class disjunctions (aka unions) thus we can't write:
fn f<A: FileHandle | Cursor, G: Fn(A) -> ()>(g: G, pred: bool) {
So thus this is the only way to implement this example in Rust.