I figured out how to process a list of heterogeneous types constrained by a single class:
data Ex c = forall a. (c a) => Ex a
forEx :: [Ex c] -> (forall a. c a => a -> b) -> [b]
forEx [] _ = []
forEx (Ex a:r) f = f a : forEx r f
> forEx @Show [Ex 3, Ex (), Ex True] show
["3","()","True"]
Looks great, but in real life instead of show function would more complicated one relying on more than 1 constraint. Going further by analogy doesn't work:
Attempt 1:
forEx @(Show, Eq) [Ex 3, Ex (), Ex True] show
<interactive>:85:8: error:
• Expected kind ‘* -> Constraint’, but ‘(Show, Eq)’ has kind ‘*’
Attempt 2:
type ShowEq c = (Show c, Eq c)
> forEx @ShowEq [Ex 3, Ex (), Ex True] show
<interactive>:87:1: error:
• The type synonym ‘ShowEq’ should have 1 argument, but has been given none
Attempt 3 works, but defining dummy class and instance for one time use is to clumsy:
class (Show a, Eq a) => ShowEq1 a
instance (Show a, Eq a) => ShowEq1 a
forEx @ShowEq1 [Ex (3::Int), Ex (), Ex True] show
["3","()","True"]