I'm trying to create a function that gets a variadic function as an argument, i.e.
func :: (a -> ... -> a) -> a
how can I accomplish this?
I've read about polyvariadic functions and I'm sure that Oleg already did it, however I'm lost trying to apply the pattern on a function with a variadic function as an argument. Especially Olegs approach seems to work with glasgow extensions only and I want the solution to work in pure Haskell 98 (like Text.Printf does).
The reason that I ask is that I'm trying to build a function which takes a boolean function as an argument and checks whether it is a tautology, i.e.
isTautology :: (Bool -> ... -> Bool) -> Bool
so that one could type:
isTautology (\x -> x && not x)
isTautology (\x y -> x && y || not y)
My problem is that I keep reading about the trick was to make the return type a type variable (so that it can be the result or another function), but my return type is fixed (Bool).
The trick is to make a type class for which you will define an instance for functions, and an instance for the return type. The fact that it's a
Bool
is not a problem at all.We're trying to write a function which takes a variadic argument and returns a
Bool
, so we'll define a type class with such a function.Next, we define an instance for the return type of the variadic function. In this case, that's
Bool
.The key part is the next instance for functions that take a
Bool
argument, and whose return type is some type from our class. That way, this instance will be applied multiple times if a function takes multiple arguments.Writing it this way requires
FlexibleInstances
because of theBool
in the second instance head. To do the same with pure Haskell 98, we'll need to use a suitably-constrained type variable instead. We can for example useBounded
andEnum
(there are instances for both forBool
), or you can make your own class that will let you construct the appropriate inputs.And we're done. Let's try it out: