This is the second article in the series "Theory of Categories for Programmers."Category is a very simple concept.
A category consists of objects and arrows that are directed between them. Therefore, categories are so easy to imagine graphically. The object can be drawn in the form of a circle or a point, and the arrows can be simply arrows between them. (Just for a change, I will from time to time draw objects like piglets and arrows, like fireworks.) But the essence of the category is composition. Or, if you prefer, the essence of the composition is a category. The arrows are arranged so that if you have an arrow from object A to object B, and another arrow from object B to C, then there must be an arrow, - their composition, - from A to C.
')

In the category, if there is an arrow from A to B and an arrow from B to C, then there must be an arrow from A to C, which is called their composition. This scheme is not a complete definition of the category because there are not enough identical morphisms (see below).
Arrows as a function
Already too much abstract nonsense? Do not despair. Let's look at the examples. Think of the arrows, which are also called morphisms, as functions. You have a function f, which takes an argument of type A and returns a value of type B. There is also another function g, which takes B and returns C. You can combine them by passing the result from f to g. You have just described a new function that accepts A and returns C.
In mathematics, such a composition is indicated by a small circle between the functions: g∘f. Pay attention to the order of the composition from right to left. This is confusing to some people. You may see similarities with the notation of pipes in Unix, for example:
lsof | grep Chrome
>> F#, -. Haskell -. , g∘f «g f.»
. f, A B:
B f(A a);
:
C g(B b);
:
C g_after_f(A a)
{
return g(f(a));
}
-: g(f(a));, .
, ++, , .
: ++14 ( , ):template <typename T>
struct function_arg: public function_arg<decltype(&T::operator())> {};
template<typename ReturnType, typename Arg>
struct function_arg<ReturnType(Arg) const> {
using type = Arg;
};
template<typename ClassType, typename ReturnType, typename Arg>
struct function_arg<ReturnType(ClassType::*)(Arg) const> {
using type = Arg;
};
template<typename T>
using function_arg_t = typename function_arg<T>::type;
template<typename F, typename G>
auto compose(F&& f, G&& g) {
return [f = std::forward<F>(f), g = std::forward<G>(g)]
(function_arg_t<F>&& a) {return g(f(std::forward<function_arg_t<F>>(a)));};
}
, Haskell. :
f :: A -> B
:
g :: B -> C
:
g . f
, Haskell, C++ . Haskell Unicode , :
g ∘ f
Unicode:
f ∷ A → B
Haskell : « ...» . ( Unicode).
, .
1. . , f, g h, ( , ), , . , :
h∘(g∘f) = (h∘g)∘f = h∘g∘f
() Haskell:
f :: A -> B
g :: B -> C
h :: C -> D
h . (g . f) == (h . g) . f == h . g . f
«» , .
, , .
2. A , . . — , , A A , . idA ( ). , f A B,
f∘idA = f
idB∘f = f
, , . , , . C++ :
template<class T> T id(T x) { return x; }
: -, :template<class T> auto id(T&& x) { return std::forward<T>(x); }
, C++ , , ( , , , , , ).
Haskell, — ( Prelude). :
id :: a -> a
id x = x
, Haskell . , . , , .
Haskell — : x. . , , . — , . , ( , ).
— . — , x.
Haskell.
( , -Haskell), :
f . id == f
id . f == f
: - — , ? , ? — . , , .
, id, . , , , . , , . — , . — .
: (). . , .
—
. - . , , : ? , , , . : ? , — , . « x EAX.» , , , — - . ( , ). ? . , , . , , . : . , .
. . . , « - », , 7 ± 2 «» . , , . , . , , , . , , . , .
?
, , . ( , , — , , ).
— , , .
— , , .
, , , , . - , — . — . , .
— , . . , — — . -, ( , ).
: , :) - , ( , ), , . , , , .
.
::
,P.S. , ,
, : .