To be precise, I've implemented both a dyadic `~` constraint; and the idea from M.P. Jones & Diatchki 2008, end of §3.3 http://web.cecs.pdx.edu/~mpj/pubs/fundeps-design.html
f1 :: Bool ~ b => b -> Bool -- dyadic f2 :: C Int ~ b => b -> Bool -- Class C
class C a b | a -> b
class (~) a b | a -> b, b -> a instance (~) b b
This is not introducing type operators nor class-as-operator in general. The `~` is hard-coded syntax. A constraint `C Int ~ b =>` desugars to plain `C Int b =>` so the syntax is to help the reader. (There's no check whether `C` has a FunDep, nor whether the second param is the dependent.) This does make the syntax ambiguous; the implementation is ugly: dyadic `Maybe Int ~ b =>` is not distinct from a class constraint; the resolution is to look up the LHS's head in known class names. Note the semantics for dyadic `~` is not as convoluted as `TypeCast` from the HList paper [Kiselyov et al 2003, Appendix D] This has needed solving a long-standing limitation with FunDeps https://gitlab.haskell.org/ghc/ghc/-/work_items/9627#note_697088 Upon meeting the equation for `f1, f2` instantiate skolems from the given signatures, as usual; then immediately `improve( )` the type from any classes/their FunDeps _as appear in the given signature_, and only from there. In Hugs terms this is improving the 'Expected type'. (The Trac Issues uses ghc terminology 'Rigid tyvar'.) This improvement also applies for instance decls: if the class has a super-constraint with a FunDep; or the method has a constraint with a FunDep; improve that upon substituting the type(s) from the instance head. Thus can support a constrained Functor/Monad/etc:
class Funkytor tb where funkyMap :: t b ~ tb => (a -> b) -> t a -> t b
instance Ord b => Funkytor (Data.Set.Set b) where funkyMap f xs = Data.Set.fromList $ fmap f (Data.Set.toList xs)
`Funkytor` like that can't be defined using `TypeCast`: the `t b ~ tb` isn't applied eagerly enough. AntC