This simply says that a normal function 'a -> b' is a function like thing in the following way:
- its input is of type 'a'
- its output is of type 'b'
- it can be mapped to our 'Functions' data type by using the 'One' constructor. 'funcOf' shoehorns both normal functions and chains of :<|>-separated functions into this concept of 'function like thing'.
Now, the fancier instance:
> instance (Func t, Func t', Arg t ~ Arg t')
> => Func (t :<|> t') where
> type Arg (t :<|> t') = Arg t
> type Out (t :<|> t') = Out t :<|> Out t'
> funcOf (t :<|> t') = More (funcOf t) (funcOf t')
It says that if we have two "function like things" t and t', and that they take the same type of input (Arg t ~ Arg t' means Arg t must be equal to Arg t'), then we can consider t :<|> t' as a function like thing too, in the following way:
- the input type for both t and t' being the same, we can simply take a single argument of that type and make it the input to both of our "function like things".
- the output type of " t :<|> t' " is " output-type-of-t :<|> output-type-of-t' "; i.e we simply group together with :<|> the result of t and t'
- to represent t :<|> t' using our 'Functions' data type, we use the 'More' constructor (the Arg t ~ Arg t' bit allows us to, because the 'More' constructor will see that t and t' have the same input type), by storing the result of recursively calling 'funcOf' on t and t'. Put in a simpler way, if we have two "function like things" (which can therefore be represented as a value of type 'Functions a t b'), then we represent t :<|> t' using More representation-of-t representation-of-t'.
Finally, the code that actually matters:
> runFunctions :: Functions a t b -> a -> b
> runFunctions (One f) x = f x
> runFunctions (More f1 f2) x =
> runFunctions f1 x :<|> runFunctions f2 x
>
> applyTo :: Func t => Arg t -> t -> Out t
> applyTo arg t = runFunctions (funcOf t) arg
runFunctions takes a 'Functions a t b' value (recall that a = input type, t = type of the function like thing, b = return type) along with some input of type 'a', and returns a 'b'. It does so by handling the "just a normal function" and "two function like things put together" cases separately.
applyTo finally wraps it all up and calls 'runFunctions' on the representation of any "function like thing", which can be a simple function or many of them separated by :<|>s.
I suspect a lot of the technical details will be a bit hard to understand and I'm not claiming any of this is simple. It took me some time to be able to understand that kind of code, and even more time to be able to write it. Please do not feel intimidated by any of this. You'll understand it all eventually (if it's not already the case).
All you need to do to use it is stick that code in some module of your project, and just use 'applyTo' when you need it. It's unfortunate that one has to go through these hoops to do something so simple, yes. I'm hoping future servant versions will have ready to use functions out of the box to answer those needs, or better, a more general solution for traversing and transforming "chains of :<|> separated stuffs" with just a few simple and approachable functions.