|
||||
File indexing completed on 2025-01-18 09:37:58
0001 /*! 0002 @file 0003 Forward declares `boost::hana::Monad`. 0004 0005 Copyright Louis Dionne 2013-2022 0006 Distributed under the Boost Software License, Version 1.0. 0007 (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 0008 */ 0009 0010 #ifndef BOOST_HANA_FWD_CONCEPT_MONAD_HPP 0011 #define BOOST_HANA_FWD_CONCEPT_MONAD_HPP 0012 0013 #include <boost/hana/config.hpp> 0014 0015 0016 namespace boost { namespace hana { 0017 //! @ingroup group-concepts 0018 //! @defgroup group-Monad Monad 0019 //! The `Monad` concept represents `Applicative`s with the ability to 0020 //! flatten nested levels of structure. 0021 //! 0022 //! Historically, Monads are a construction coming from category theory, 0023 //! an abstract branch of mathematics. The functional programming 0024 //! community eventually discovered how Monads could be used to 0025 //! formalize several useful things like side effects, which led 0026 //! to the wide adoption of Monads in that community. However, even 0027 //! in a multi-paradigm language like C++, there are several constructs 0028 //! which turn out to be Monads, like `std::optional`, `std::vector` and 0029 //! others. 0030 //! 0031 //! Everybody tries to introduce `Monad`s with a different analogy, and 0032 //! most people fail. This is called the [Monad tutorial fallacy][1]. We 0033 //! will try to avoid this trap by not presenting a specific intuition, 0034 //! and we will instead present what monads are mathematically. 0035 //! For specific intuitions, we will let readers who are new to this 0036 //! concept read one of the many excellent tutorials available online. 0037 //! Understanding Monads might take time at first, but once you get it, 0038 //! a lot of patterns will become obvious Monads; this enlightening will 0039 //! be your reward for the hard work. 0040 //! 0041 //! There are different ways of defining a Monad; Haskell uses a function 0042 //! called `bind` (`>>=`) and another one called `return` (it has nothing 0043 //! to do with C++'s `return` statement). They then introduce relationships 0044 //! that must be satisfied for a type to be a Monad with those functions. 0045 //! Mathematicians sometimes use a function called `join` and another one 0046 //! called `unit`, or they also sometimes use other category theoretic 0047 //! constructions like functor adjunctions and the Kleisli category. 0048 //! 0049 //! This library uses a composite approach. First, we use the `flatten` 0050 //! function (equivalent to `join`) along with the `lift` function from 0051 //! `Applicative` (equivalent to `unit`) to introduce the notion of 0052 //! monadic function composition. We then write the properties that must 0053 //! be satisfied by a Monad using this monadic composition operator, 0054 //! because we feel it shows the link between Monads and Monoids more 0055 //! clearly than other approaches. 0056 //! 0057 //! Roughly speaking, we will say that a `Monad` is an `Applicative` which 0058 //! also defines a way to compose functions returning a monadic result, 0059 //! as opposed to only being able to compose functions returning a normal 0060 //! result. We will then ask for this composition to be associative and to 0061 //! have a neutral element, just like normal function composition. For 0062 //! usual composition, the neutral element is the identity function `id`. 0063 //! For monadic composition, the neutral element is the `lift` function 0064 //! defined by `Applicative`. This construction is made clearer in the 0065 //! laws below. 0066 //! 0067 //! @note 0068 //! Monads are known to be a big chunk to swallow. However, it is out of 0069 //! the scope of this documentation to provide a full-blown explanation 0070 //! of the concept. The [Typeclassopedia][2] is a nice Haskell-oriented 0071 //! resource where more information about Monads can be found. 0072 //! 0073 //! 0074 //! Minimal complete definitions 0075 //! ---------------------------- 0076 //! First, a `Monad` must be both a `Functor` and an `Applicative`. 0077 //! Also, an implementation of `flatten` or `chain` satisfying the 0078 //! laws below for monadic composition must be provided. 0079 //! 0080 //! @note 0081 //! The `ap` method for `Applicatives` may be derived from the minimal 0082 //! complete definition of `Monad` and `Functor`; see below for more 0083 //! information. 0084 //! 0085 //! 0086 //! Laws 0087 //! ---- 0088 //! To simplify writing the laws, we use the comparison between functions. 0089 //! For two functions `f` and `g`, we define 0090 //! @code 0091 //! f == g if and only if f(x) == g(x) for all x 0092 //! @endcode 0093 //! 0094 //! With the usual composition of functions, we are given two functions 0095 //! @f$ f : A \to B @f$ and @f$ g : B \to C @f$, and we must produce a 0096 //! new function @f$ compose(g, f) : A \to C @f$. This composition of 0097 //! functions is associative, which means that 0098 //! @code 0099 //! compose(h, compose(g, f)) == compose(compose(h, g), f) 0100 //! @endcode 0101 //! 0102 //! Also, this composition has an identity element, which is the identity 0103 //! function. This simply means that 0104 //! @code 0105 //! compose(f, id) == compose(id, f) == f 0106 //! @endcode 0107 //! 0108 //! This is probably nothing new if you are reading the `Monad` laws. 0109 //! Now, we can observe that the above is equivalent to saying that 0110 //! functions with the composition operator form a `Monoid`, where the 0111 //! neutral element is the identity function. 0112 //! 0113 //! Given an `Applicative` `F`, what if we wanted to compose two functions 0114 //! @f$ f : A \to F(B) @f$ and @f$ g : B \to F(C) @f$? When the 0115 //! `Applicative` `F` is also a `Monad`, such functions taking normal 0116 //! values but returning monadic values are called _monadic functions_. 0117 //! To compose them, we obviously can't use normal function composition, 0118 //! since the domains and codomains of `f` and `g` do not match properly. 0119 //! Instead, we'll need a new operator -- let's call it `monadic_compose`: 0120 //! @f[ 0121 //! \mathtt{monadic\_compose} : 0122 //! (B \to F(C)) \times (A \to F(B)) \to (A \to F(C)) 0123 //! @f] 0124 //! 0125 //! How could we go about implementing this function? Well, since we know 0126 //! `F` is an `Applicative`, the only functions we have are `transform` 0127 //! (from `Functor`), and `lift` and `ap` (from `Applicative`). Hence, 0128 //! the only thing we can do at this point while respecting the signatures 0129 //! of `f` and `g` is to set (for `x` of type `A`) 0130 //! @code 0131 //! monadic_compose(g, f)(x) = transform(f(x), g) 0132 //! @endcode 0133 //! 0134 //! Indeed, `f(x)` is of type `F(B)`, so we can map `g` (which takes `B`'s) 0135 //! on it. Doing so will leave us with a result of type `F(F(C))`, but what 0136 //! we wanted was a result of type `F(C)` to respect the signature of 0137 //! `monadic_compose`. If we had a joker of type @f$ F(F(C)) \to F(C) @f$, 0138 //! we could simply set 0139 //! @code 0140 //! monadic_compose(g, f)(x) = joker(transform(f(x), g)) 0141 //! @endcode 0142 //! 0143 //! and we would be happy. It turns out that `flatten` is precisely this 0144 //! joker. Now, we'll want our joker to satisfy some properties to make 0145 //! sure this composition is associative, just like our normal composition 0146 //! was. These properties are slightly cumbersome to specify, so we won't 0147 //! do it here. Also, we'll need some kind of neutral element for the 0148 //! composition. This neutral element can't be the usual identity function, 0149 //! because it does not have the right type: our neutral element needs to 0150 //! be a function of type @f$ X \to F(X) @f$ but the identity function has 0151 //! type @f$ X \to X @f$. It is now the right time to observe that `lift` 0152 //! from `Applicative` has exactly the right signature, and so we'll take 0153 //! this for our neutral element. 0154 //! 0155 //! We are now ready to formulate the `Monad` laws using this composition 0156 //! operator. For a `Monad` `M` and functions @f$ f : A \to M(B) @f$, 0157 //! @f$ g : B \to M(C) @f$ and @f$ h : C \to M(D) @f$, the following 0158 //! must be satisfied: 0159 //! @code 0160 //! // associativity 0161 //! monadic_compose(h, monadic_compose(g, f)) == monadic_compose(monadic_compose(h, g), f) 0162 //! 0163 //! // right identity 0164 //! monadic_compose(f, lift<M(A)>) == f 0165 //! 0166 //! // left identity 0167 //! monadic_compose(lift<M(B)>, f) == f 0168 //! @endcode 0169 //! 0170 //! which is to say that `M` along with monadic composition is a Monoid 0171 //! where the neutral element is `lift`. 0172 //! 0173 //! 0174 //! Refined concepts 0175 //! ---------------- 0176 //! 1. `Functor` 0177 //! 2. `Applicative` (free implementation of `ap`)\n 0178 //! When the minimal complete definition for `Monad` and `Functor` are 0179 //! both satisfied, it is possible to implement `ap` by setting 0180 //! @code 0181 //! ap(fs, xs) = chain(fs, [](auto f) { 0182 //! return transform(xs, f); 0183 //! }) 0184 //! @endcode 0185 //! 0186 //! 0187 //! Concrete models 0188 //! --------------- 0189 //! `hana::lazy`, `hana::optional`, `hana::tuple` 0190 //! 0191 //! 0192 //! [1]: https://byorgey.wordpress.com/2009/01/12/abstraction-intuition-and-the-monad-tutorial-fallacy/ 0193 //! [2]: https://wiki.haskell.org/Typeclassopedia#Monad 0194 template <typename M> 0195 struct Monad; 0196 }} // end namespace boost::hana 0197 0198 #endif // !BOOST_HANA_FWD_CONCEPT_MONAD_HPP
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |