We'll explain this idea before
Control Flow-related type classes so that you understand a notation we'll use in them.
Let's say I have two functions:
(\x -> x + 1) (\y -> y * 10)
If we want to apply an argument to the first and pass its output into the second, we would have to write something ugly-looking:
(\x -> (\y -> y * 10) (x + 1) )
What we mean is something like this
f = (\x -> x + 1) g = (\y -> y * 10) expression = (\arg -> g (f arg))
We have just defined function composition, which can be written in such a way to reduce "noise:"
-- The arrow determines where the output goes (\a -> g (f a)) == (g <<< f) (\a -> g (f a)) == (f >>> g)
Moreover, sometimes we want a function that returns the input:
(\x -> x) -- so that we can use it like... (\x -> x) 4 == 4
We call this function,
(\x -> x) == identity -- same thing identity 4 == 4
If we were to turn
compose into a function, it would appear with the type signature below:
compose :: forall a b c. (b -> c) -> (a -> b) -> (a -> c) -- However, "->" is just sugar syntax for Function: compose :: forall a b c. Function b c -> Function a c -> Function a c -- Notice that Function appears to be just another data structure. -- If it works for that data structure, why not generalize it for any data structure? compose :: forall f a b c. f b c -> f a b -> f a c -- Let's rename our generics, so that it starts with `a` rather than `f`: compose :: forall a b c d. a c d -> a b c -> a b d -- We'll line up the types for easier reading: compose :: forall a b c. (b -> c) -> (a -> b) -> (a -> c) compose :: forall a b c. Function b c -> Function a b -> Function a c compose :: forall f a b c. f b c -> f a b -> f a c compose :: forall a b c d. a c d -> a b c -> a b d -- We've now just defined the function `compose` for Semigroupoid: class Semigroupoid a where compose :: forall b c d. a c d -> a b c -> a b d -- Doing the same for identity is trivial: identity :: forall a. a -> a identity :: forall a. Function a a identity :: forall f a. f a a identity :: forall a b. a b b class (Semigroupoid a) <= Category a where -- we'll use 't' instead of 'b' identity :: forall t. a t t
Here's the docs. You likely won't be using these that often (unless perhaps you're designing a library), but it's good to know of them:
You will see
g <<< g or its flipped version
g >>> f a lot and we'll use it in the upcoming files.