fix.hpp 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. /*!
  2. @file
  3. Defines `boost::hana::fix`.
  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_FUNCTIONAL_FIX_HPP
  9. #define BOOST_HANA_FUNCTIONAL_FIX_HPP
  10. #include <boost/hana/config.hpp>
  11. #include <boost/hana/detail/create.hpp>
  12. #include <utility>
  13. BOOST_HANA_NAMESPACE_BEGIN
  14. //! @ingroup group-functional
  15. //! Return a function computing the fixed point of a function.
  16. //!
  17. //! `fix` is an implementation of the [Y-combinator][], also called the
  18. //! fixed-point combinator. It encodes the idea of recursion, and in fact
  19. //! any recursive function can be written in terms of it.
  20. //!
  21. //! Specifically, `fix(f)` is a function such that
  22. //! @code
  23. //! fix(f)(x...) == f(fix(f), x...)
  24. //! @endcode
  25. //!
  26. //! This definition allows `f` to use its first argument as a continuation
  27. //! to call itself recursively. Indeed, if `f` calls its first argument
  28. //! with `y...`, it is equivalent to calling `f(fix(f), y...)` per the
  29. //! above equation.
  30. //!
  31. //! Most of the time, it is more convenient and efficient to define
  32. //! recursive functions without using a fixed-point combinator. However,
  33. //! there are some cases where `fix` provides either more flexibility
  34. //! (e.g. the ability to change the callback inside `f`) or makes it
  35. //! possible to write functions that couldn't be defined recursively
  36. //! otherwise.
  37. //!
  38. //! @param f
  39. //! A function called as `f(self, x...)`, where `x...` are the arguments
  40. //! in the `fix(f)(x...)` expression and `self` is `fix(f)`.
  41. //!
  42. //! ### Example
  43. //! @include example/functional/fix.cpp
  44. //!
  45. //! [Y-combinator]: http://en.wikipedia.org/wiki/Fixed-point_combinator
  46. #ifdef BOOST_HANA_DOXYGEN_INVOKED
  47. constexpr auto fix = [](auto&& f) {
  48. return [perfect-capture](auto&& ...x) -> decltype(auto) {
  49. return forwarded(f)(fix(f), forwarded(x)...);
  50. };
  51. };
  52. #else
  53. template <typename F>
  54. struct fix_t;
  55. constexpr detail::create<fix_t> fix{};
  56. template <typename F>
  57. struct fix_t {
  58. F f;
  59. template <typename ...X>
  60. constexpr decltype(auto) operator()(X&& ...x) const&
  61. { return f(fix(f), static_cast<X&&>(x)...); }
  62. template <typename ...X>
  63. constexpr decltype(auto) operator()(X&& ...x) &
  64. { return f(fix(f), static_cast<X&&>(x)...); }
  65. template <typename ...X>
  66. constexpr decltype(auto) operator()(X&& ...x) &&
  67. { return std::move(f)(fix(f), static_cast<X&&>(x)...); }
  68. };
  69. #endif
  70. BOOST_HANA_NAMESPACE_END
  71. #endif // !BOOST_HANA_FUNCTIONAL_FIX_HPP