Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:37:58

0001 /*!
0002 @file
0003 Defines `boost::hana::curry`.
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_FUNCTIONAL_CURRY_HPP
0011 #define BOOST_HANA_FUNCTIONAL_CURRY_HPP
0012 
0013 #include <boost/hana/config.hpp>
0014 #include <boost/hana/detail/decay.hpp>
0015 #include <boost/hana/functional/apply.hpp>
0016 #include <boost/hana/functional/partial.hpp>
0017 
0018 #include <cstddef>
0019 #include <type_traits>
0020 #include <utility>
0021 
0022 
0023 namespace boost { namespace hana {
0024     //! @ingroup group-functional
0025     //! Curry a function up to the given number of arguments.
0026     //!
0027     //! [Currying][Wikipedia.currying] is a technique in which we consider a
0028     //! function taking multiple arguments (or, equivalently, a tuple of
0029     //! arguments), and turn it into a function which takes a single argument
0030     //! and returns a function to handle the remaining arguments. To help
0031     //! visualize, let's denote the type of a function `f` which takes
0032     //! arguments of types `X1, ..., Xn` and returns a `R` as
0033     //! @code
0034     //!     (X1, ..., Xn) -> R
0035     //! @endcode
0036     //!
0037     //! Then, currying is the process of taking `f` and turning it into an
0038     //! equivalent function (call it `g`) of type
0039     //! @code
0040     //!     X1 -> (X2 -> (... -> (Xn -> R)))
0041     //! @endcode
0042     //!
0043     //! This gives us the following equivalence, where `x1`, ..., `xn` are
0044     //! objects of type `X1`, ..., `Xn` respectively:
0045     //! @code
0046     //!     f(x1, ..., xn) == g(x1)...(xn)
0047     //! @endcode
0048     //!
0049     //! Currying can be useful in several situations, especially when working
0050     //! with higher-order functions.
0051     //!
0052     //! This `curry` utility is an implementation of currying in C++.
0053     //! Specifically, `curry<n>(f)` is a function such that
0054     //! @code
0055     //!     curry<n>(f)(x1)...(xn) == f(x1, ..., xn)
0056     //! @endcode
0057     //!
0058     //! Note that the `n` has to be specified explicitly because the existence
0059     //! of functions with variadic arguments in C++ make it impossible to know
0060     //! when currying should stop.
0061     //!
0062     //! Unlike usual currying, this implementation also allows a curried
0063     //! function to be called with several arguments at a time. Hence, the
0064     //! following always holds
0065     //! @code
0066     //!     curry<n>(f)(x1, ..., xk) == curry<n - k>(f)(x1)...(xk)
0067     //! @endcode
0068     //!
0069     //! Of course, this requires `k` to be less than or equal to `n`; failure
0070     //! to satisfy this will trigger a static assertion. This syntax is
0071     //! supported because it makes curried functions usable where normal
0072     //! functions are expected.
0073     //!
0074     //! Another "extension" is that `curry<0>(f)` is supported: `curry<0>(f)`
0075     //! is a nullary function; whereas the classical definition for currying
0076     //! seems to leave this case undefined, as nullary functions don't make
0077     //! much sense in purely functional languages.
0078     //!
0079     //!
0080     //! Example
0081     //! -------
0082     //! @include example/functional/curry.cpp
0083     //!
0084     //!
0085     //! [Wikipedia.currying]: http://en.wikipedia.org/wiki/Currying
0086 #ifdef BOOST_HANA_DOXYGEN_INVOKED
0087     template <std::size_t n>
0088     constexpr auto curry = [](auto&& f) {
0089         return [perfect-capture](auto&& x1) {
0090             return [perfect-capture](auto&& x2) {
0091                 ...
0092                     return [perfect-capture](auto&& xn) -> decltype(auto) {
0093                         return forwarded(f)(
0094                             forwarded(x1), forwarded(x2), ..., forwarded(xn)
0095                         );
0096                     };
0097             };
0098         };
0099     };
0100 #else
0101     template <std::size_t n, typename F>
0102     struct curry_t;
0103 
0104     template <std::size_t n>
0105     struct make_curry_t {
0106         template <typename F>
0107         constexpr curry_t<n, typename detail::decay<F>::type>
0108         operator()(F&& f) const { return {static_cast<F&&>(f)}; }
0109     };
0110 
0111     template <std::size_t n>
0112     BOOST_HANA_INLINE_VARIABLE constexpr make_curry_t<n> curry{};
0113 
0114     namespace curry_detail { namespace {
0115         template <std::size_t n>
0116         constexpr make_curry_t<n> curry_or_call{};
0117 
0118         template <>
0119         constexpr auto curry_or_call<0> = apply;
0120     }}
0121 
0122     template <std::size_t n, typename F>
0123     struct curry_t {
0124         F f;
0125 
0126         template <typename ...X>
0127         constexpr decltype(auto) operator()(X&& ...x) const& {
0128             static_assert(sizeof...(x) <= n,
0129             "too many arguments provided to boost::hana::curry");
0130             return curry_detail::curry_or_call<n - sizeof...(x)>(
0131                 partial(f, static_cast<X&&>(x)...)
0132             );
0133         }
0134 
0135         template <typename ...X>
0136         constexpr decltype(auto) operator()(X&& ...x) & {
0137             static_assert(sizeof...(x) <= n,
0138             "too many arguments provided to boost::hana::curry");
0139             return curry_detail::curry_or_call<n - sizeof...(x)>(
0140                 partial(f, static_cast<X&&>(x)...)
0141             );
0142         }
0143 
0144         template <typename ...X>
0145         constexpr decltype(auto) operator()(X&& ...x) && {
0146             static_assert(sizeof...(x) <= n,
0147             "too many arguments provided to boost::hana::curry");
0148             return curry_detail::curry_or_call<n - sizeof...(x)>(
0149                 partial(std::move(f), static_cast<X&&>(x)...)
0150             );
0151         }
0152     };
0153 
0154     template <typename F>
0155     struct curry_t<0, F> {
0156         F f;
0157 
0158         constexpr decltype(auto) operator()() const&
0159         { return f(); }
0160 
0161         constexpr decltype(auto) operator()() &
0162         { return f(); }
0163 
0164         constexpr decltype(auto) operator()() &&
0165         { return std::move(f)(); }
0166     };
0167 #endif
0168 }} // end namespace boost::hana
0169 
0170 #endif // !BOOST_HANA_FUNCTIONAL_CURRY_HPP