lazy.hpp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. /*!
  2. @file
  3. Forward declares `boost::hana::lazy`.
  4. @copyright Louis Dionne 2013-2017
  5. Distributed under the Boost Software License, Version 1.0.
  6. (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
  7. */
  8. #ifndef BOOST_HANA_FWD_LAZY_HPP
  9. #define BOOST_HANA_FWD_LAZY_HPP
  10. #include <boost/hana/config.hpp>
  11. #include <boost/hana/fwd/core/make.hpp>
  12. BOOST_HANA_NAMESPACE_BEGIN
  13. //! @ingroup group-datatypes
  14. //! `hana::lazy` implements superficial laziness via a monadic interface.
  15. //!
  16. //! It is important to understand that the laziness implemented by `lazy`
  17. //! is only superficial; only function applications made inside the `lazy`
  18. //! monad can be made lazy, not all their subexpressions.
  19. //!
  20. //!
  21. //! @note
  22. //! The actual representation of `hana::lazy` is completely
  23. //! implementation-defined. Lazy values may only be created through
  24. //! `hana::make_lazy`, and they can be stored in variables using
  25. //! `auto`, but any other assumption about the representation of
  26. //! `hana::lazy<...>` should be avoided. In particular, one should
  27. //! not rely on the fact that `hana::lazy<...>` can be pattern-matched
  28. //! on, because it may be a dependent type.
  29. //!
  30. //!
  31. //! Modeled concepts
  32. //! ----------------
  33. //! 1. `Functor`\n
  34. //! Applying a function over a lazy value with `transform` returns the
  35. //! result of applying the function, as a lazy value.
  36. //! @include example/lazy/functor.cpp
  37. //!
  38. //! 2. `Applicative`\n
  39. //! A normal value can be lifted into a lazy value by using `lift<lazy_tag>`.
  40. //! A lazy function can be lazily applied to a lazy value by using `ap`.
  41. //!
  42. //! 3. `Monad`\n
  43. //! The `lazy` monad allows combining lazy computations into larger
  44. //! lazy computations. Note that the `|` operator can be used in place
  45. //! of the `chain` function.
  46. //! @include example/lazy/monad.cpp
  47. //!
  48. //! 4. `Comonad`\n
  49. //! The `lazy` comonad allows evaluating a lazy computation to get its
  50. //! result and lazily applying functions taking lazy inputs to lazy
  51. //! values. This [blog post][1] goes into more details about lazy
  52. //! evaluation and comonads.
  53. //! @include example/lazy/comonad.cpp
  54. //!
  55. //!
  56. //! @note
  57. //! `hana::lazy` only models a few concepts because providing more
  58. //! functionality would require evaluating the lazy values in most cases.
  59. //! Since this raises some issues such as side effects and memoization,
  60. //! the interface is kept minimal.
  61. //!
  62. //!
  63. //! [1]: http://ldionne.com/2015/03/16/laziness-as-a-comonad
  64. #ifdef BOOST_HANA_DOXYGEN_INVOKED
  65. template <typename implementation_defined>
  66. struct lazy {
  67. //! Equivalent to `hana::chain`.
  68. template <typename ...T, typename F>
  69. friend constexpr auto operator|(lazy<T...>, F);
  70. };
  71. #else
  72. // We do not _actually_ define the lazy<...> type. Per the documentation,
  73. // users can't rely on it being anything, and so they should never use
  74. // it explicitly. The implementation in <boost/hana/lazy.hpp> is much
  75. // simpler if we use different types for lazy calls and lazy values.
  76. #endif
  77. //! Tag representing `hana::lazy`.
  78. //! @relates hana::lazy
  79. struct lazy_tag { };
  80. //! Lifts a normal value to a lazy one.
  81. //! @relates hana::lazy
  82. //!
  83. //! `make<lazy_tag>` can be used to lift a normal value or a function call
  84. //! into a lazy expression. Precisely, `make<lazy_tag>(x)` is a lazy value
  85. //! equal to `x`, and `make<lazy_tag>(f)(x1, ..., xN)` is a lazy function
  86. //! call that is equal to `f(x1, ..., xN)` when it is `eval`uated.
  87. //!
  88. //! @note
  89. //! It is interesting to note that `make<lazy_tag>(f)(x1, ..., xN)` is
  90. //! equivalent to
  91. //! @code
  92. //! ap(make<lazy_tag>(f), lift<lazy_tag>(x1), ..., lift<lazy_tag>(xN))
  93. //! @endcode
  94. //! which in turn is equivalent to `make<lazy_tag>(f(x1, ..., xN))`, except
  95. //! for the fact that the inner call to `f` is evaluated lazily.
  96. //!
  97. //!
  98. //! Example
  99. //! -------
  100. //! @include example/lazy/make.cpp
  101. #ifdef BOOST_HANA_DOXYGEN_INVOKED
  102. template <>
  103. constexpr auto make<lazy_tag> = [](auto&& x) {
  104. return lazy<implementation_defined>{forwarded(x)};
  105. };
  106. #endif
  107. //! Alias to `make<lazy_tag>`; provided for convenience.
  108. //! @relates hana::lazy
  109. //!
  110. //! Example
  111. //! -------
  112. //! @include example/lazy/make.cpp
  113. constexpr auto make_lazy = make<lazy_tag>;
  114. BOOST_HANA_NAMESPACE_END
  115. #endif // !BOOST_HANA_FWD_LAZY_HPP