KK>None%&*DOT# has the following data definition: ^data Poly (c :: * -> Constraint) where Poly :: { getPoly :: (forall a. c a => a) } -> Poly cDHaddock has trouble parsing it, presumably because it's confused by (c :: * -> Constraint).:Here's a first example, which is a polymorphic version of : spolyToInteger = Poly @((IsFunc 1) &&& ((Arg 0) `IxConstrainBy` Integral) &&& ((Result 1) `IxIs` Integer)) toIntegerFSo lets look from left to right for what constraints we're passing to  polyToInteger:  (IsFunc 1)A constrains a type to be a function, in this case of one variable "((Arg 0) `IxConstrainBy` Integral) 03 specifies the first argument (this is zero based) E constrains the argument given to the constraint given, in this case  ((Result 1) `IxIs` Integer)So the # (of the one argument function) is .So then we can do: 4getPoly polyToInteger (10 :: Int) -- (10 :: Integer)'Our second example is probably simpler: Ftriple = Poly @((IsHomoFunc 1) &&& ((Arg 0) `IxConstrainBy` Num)) (*3)  is like , but ensures the two arguments are the same.$ we've already seen. Note that here: (Arg 0) `IxConstrainBy` Numand (Result 1) `IxConstrainBy` Numrhave the same effect because the first argument and the result are already constrained to have the same type from  .+Two more examples, with two arguments, are: Badd = Poly @((IsHomoFunc 2) &&& ((Arg 0) `IxConstrainBy` Num)) (+)and aeq = Poly @((IsHomoArgFunc 2) &&& ((Arg 0) `IxConstrainBy` Eq) &&& ((Result 2) `IxIs` Bool)) (==)  , unlike  O, just specifies that the arguments are identical, the result may be different.-At this point it's probably worth looking at Data.Poly.FunctionS, which has a range of convience functions for making the above definitions easier.If you've now looked at Data.Poly.Function<, you've seen two ways to define the constraints to pass to :%1) Use the convienience functions in Data.Poly.Function_ 2) Combine constraints of one variable with '(Control.ConstraintManip.&&&)' as detailed above.mBut sometimes these above two methods aren't flexible enough to generate the polymorphic constraint required. Consider   6foldl' :: Foldable t => (b -> a -> b) -> b -> t a -> bowith something this complicated, its sometimes best to define the constraint directly ourselves. So here it is: type FoldConstraint t = ( IsFunc 3 t, -- A fold is a function of three args IndexT 1 t ~ ResultT 3 t, -- The second (i.e. arg 1) is equal to the result IsFunc 2 (IndexT 0 t), -- the first argument (i.e. the fold function) is a function of two args (IndexT 0 (IndexT 0 t)) ~ (ResultT 2 (IndexT 0 t)), -- the first argument of the function which is the first argument is the same as it's third IndexT 1 t ~ (IndexT 0 (IndexT 0 t)), -- also, the first argument of the function which is the first argument is the same as the second argument of the function IsData 1 (IndexT 2 t), -- the third argument is a data type with one variable Foldable (GetConstructor1 (IndexT 2 t)), -- the constructor of that third argument is Foldable IndexC 1 0 (IndexT 2 t) ~ IndexT 1 (IndexT 0 t) -- the parameter to the constructor of Foldable is the same as the second argument of the fold function )VYou'll want to look at the package "indextype" to get some details on these functions.But if you go through the above slowly, you'll see that this constraint completely describes the sort of functions that have the same signature as  .So then we can do this: class (FoldConstraint t) => FoldConstraintC t instance (FoldConstraint t) => FoldConstraintC t pfoldl' = Poly @FoldConstraintC foldl' polyFold (Poly foldFunc) = (foldFunc (+) 0 [1,2,3], foldFunc (+) 0 [1.5,2.5,3.5], foldFunc (++) "" ["Hello", ", ", "World"])And we can then do:*(polyFold pfoldl') :: (Int, Float, String)(6,7.5,"Hello, World")VNote that this wrapping approach preserves the polymorphism until inside the function.zAt this point, you may ask, why not just define a new datatype with a polymorphic parameter each time you want to do this?Well, firstly, you'd have to define a new datatype each time you want to pass a different type of function polymorphically, which is a bit of boilerplate, although it's arguably less than this.But more importantly, having a "constraint" on the type, instead of the actual type, allows as to use that constraint to build more complex constraints.A good example of that is  .For complex functions, there can be a lot to write these constraints, but constraints are composable, so you can split out common parts.However, I have a feeling there is a mechanical way to generate these constraints using Template Haskell. This will be my next addition to the library.None9;DR%Gets the type of the constraint in a  ,polydata-core-0.1.0.0-F5SS2F1X5mmCkyNtf4tap5 Data.PolyData.Poly.IsPolyControl.IndexT.FunctionIsFuncControl.ConstraintManipArg IxConstrainByResult IsHomoFunc IsHomoArgFunc Data.Foldablefoldl'Data.Poly.FunctorhmapPolygetPolyIsPolyGetPolyConstraint $fIsPolyabaseGHC.Real toIntegerIntegral integer-gmpGHC.Integer.TypeInteger