{y     None %&*9;DORT%Gets the type of the constraint in a # 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.None*,9:;<=DOQRTThe empty constraint: Empty aalways succeeds.lHandy type class for expressing an "is equal to" constraint, because as a class it can be partially applied.For example, whilst Num is a constraint function from (* -> Constraint) such that (Num t) succeeds only if t is a Num,  Equal Int$ is a constraint function such that  (Equal Int) t succeeds only if t is an Int. For example: 0mkPolyFunc1 @Integral @(Equal Integer) toIntegerIs a polymorphic  function.3'mkPolyHomoFunc1 simply represents a function from t -> t, possibly constrained.DFor example, this is how to write a polymorphic version of "triple": mkPolyHomoFunc1 @Num (*3) D'mkPolyFunc1 is for one argument functions with differing arguments.;For example, this is how to write a polymorphic version of : 0mkPolyFunc1 @Integral @(Equal Integer) toIntegerNote that something like Just :: t -> Maybe td this convience function is not helpful for, because the two constraints you pass here are separate. 3'mkPolyHomoFunc2 simply represents a function from  t -> t -> t, possibly constrained.AFor example, this is how to write a polymorphic version of "add": mkPolyHomoFunc2 @Num (+) +'mkPolyArgFunc2 represents a function from  t -> t -> rB, with two constraints, one for the arguments, one for the result.@For example, this is how to write a polymorphic version of "eq": )mkPolyHomoArgFunc2 @Eq @(Equal Bool) (==)      None *,9:;DORTkA very generic class for a map function on heterogeneous data structures (i.e. those with differing types)."This allows you to do things like:$hmap triple (3 :: Int, 4.5 :: Float)(9 :: Int, 13.5 :: Float) takes as it's function a 1, as of course you'd want a polymorphic function.EThe return type defined in the class is very vague, indeed it's just t: to be detailed in the instances, because unlike a normal  function, how O changes the type depends a lot on the type it's applied to, there's no simple  f a -> f b.\Currently only instances are defined are for 2 and 3 tuples, nag me if you want larger ones.It's worth noting how the instances are defined, for example, for the 2 tuples, there are 3 instances defined. This is primarily to help type inference. We don't know too much about the types * will produce, but we do know, if we feed ? a pair, we should get a pair back. Likewise, if the result of , is a pair, then the input should be a pair.So we provide both instances where the input is a pair, and when the output is a pair. In both of these instances, we then in the constraints section (which happens after instance selection) ensure the other argument is also a pair.The "know both are pairs already" case just needs to be added as a specific overlapping instance so the compiler has a most specific match when it already knows both input and output are pairs.  !  !" !"#$%&'(&')*+,-./&01234'polydata-0.1.0.0-KtTot8w9Az9HbaZZK1o9Qz Data.PolyData.Poly.FunctionData.Poly.FunctorControl.IndexT.FunctionIsFuncControl.ConstraintManipArg IxConstrainByResult IsHomoFunc IsHomoArgFunc Data.Foldablefoldl'hmapIsPolyGetPolyConstraintPolygetPoly $fIsPolyaEmptyEqualmkPolyHomoFunc1 mkPolyFunc1mkPolyHomoFunc2mkPolyHomoArgFunc2$fEmptya $fEqualab$fPolyHomoFunc1Constraintscf$fPolyFunc1Constraintsc1c2f PolyFunctorPolyFunctorConstraint$fPolyFunctor(->)$fPolyFunctor(->)0$fPolyFunctor(->)1$fPolyFunctor(->)2$fPolyFunctor(->)3$fPolyFunctor(->)4baseGHC.Real toIntegerIntegral integer-gmpGHC.Integer.TypeIntegerIsPolyTPolyHomoFunc1ConstraintsPolyFunc1ConstraintsGHC.Basemap hmapTuple2 hmapTuple3