Nvwa  1.1
functional.h
Go to the documentation of this file.
1 // -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
2 // vim:tabstop=4:shiftwidth=4:expandtab:
3 
4 /*
5  * Copyright (C) 2014-2016 Wu Yongwei <adah at users dot sourceforge dot net>
6  *
7  * This software is provided 'as-is', without any express or implied
8  * warranty. In no event will the authors be held liable for any
9  * damages arising from the use of this software.
10  *
11  * Permission is granted to anyone to use this software for any purpose,
12  * including commercial applications, and to alter it and redistribute
13  * it freely, subject to the following restrictions:
14  *
15  * 1. The origin of this software must not be misrepresented; you must
16  * not claim that you wrote the original software. If you use this
17  * software in a product, an acknowledgement in the product
18  * documentation would be appreciated but is not required.
19  * 2. Altered source versions must be plainly marked as such, and must
20  * not be misrepresented as being the original software.
21  * 3. This notice may not be removed or altered from any source
22  * distribution.
23  *
24  * This file is part of Stones of Nvwa:
25  * http://sourceforge.net/projects/nvwa
26  *
27  */
28 
38 #ifndef NVWA_FUNCTIONAL_H
39 #define NVWA_FUNCTIONAL_H
40 
41 #include <functional> // std::function
42 #include <iterator> // std::begin/iterator_traits
43 #include <memory> // std::allocator
44 #include <stdexcept> // std::logic_error
45 #include <string> // std::string
46 #include <tuple> // std::tuple
47 #include <type_traits> // std::decay_t/is_const/integral_constant/...
48 #include <utility> // std::declval/forward/move/index_sequence
49 #include <vector> // std::vector
50 #include "_nvwa.h" // NVWA_NAMESPACE_*
51 
52 NVWA_NAMESPACE_BEGIN
53 
54 namespace detail {
55 
56 // Struct to check whether _T1 has a suitable reserve member function
57 // and _T2 has a suitable size member function.
58 template <class _T1, class _T2>
59 struct can_reserve
60 {
61  struct good { char dummy; };
62  struct bad { char dummy[2]; };
63  template <class _Up, void (_Up::*)(size_t)> struct _SFINAE1 {};
64  template <class _Up, size_t (_Up::*)() const> struct _SFINAE2 {};
65  template <class _Up> static good reserve(_SFINAE1<_Up, &_Up::reserve>*);
66  template <class _Up> static bad reserve(...);
67  template <class _Up> static good size(_SFINAE2<_Up, &_Up::size>*);
68  template <class _Up> static bad size(...);
69  static const bool value =
70  (sizeof(reserve<_T1>(nullptr)) == sizeof(good) &&
71  sizeof(size<_T2>(nullptr)) == sizeof(good));
72 };
73 
74 // Does nothing since can_reserve::value is false.
75 template <class _T1, class _T2>
76 void try_reserve(_T1&, const _T2&, std::false_type)
77 {
78 }
79 
80 // Reserves the destination with the source's size.
81 template <class _T1, class _T2>
82 void try_reserve(_T1& dest, const _T2& src, std::true_type)
83 {
84  dest.reserve(src.size());
85 }
86 
87 // Applies the function to indexed elements in the tuple, and combines
88 // the result as a tuple.
89 template <typename _Fn, class _Tuple, std::size_t... _I>
90 constexpr auto tuple_fmap_impl(_Fn&& f, _Tuple&& t,
91  std::index_sequence<_I...>)
92 {
93  return std::make_tuple(f(std::get<_I>(std::forward<_Tuple>(t)))...);
94 }
95 
96 // Applies the function to the given value and the indexed element of
97 // the tuple. It stops the recursion.
98 template <typename _Rs, typename _Fn, class _Tuple>
99 constexpr _Rs tuple_reduce_impl(_Fn&&, _Rs&& value, _Tuple&&,
100  std::index_sequence<>)
101 {
102  return std::forward<_Rs>(value);
103 }
104 
105 // Recursively applies the function to the given value and indexed
106 // elements of the tuple.
107 template <typename _Rs, typename _Fn, class _Tuple, std::size_t _I,
108  std::size_t... _J>
109 constexpr _Rs tuple_reduce_impl(_Fn&& f, _Rs&& value, _Tuple&& t,
110  std::index_sequence<_I, _J...>)
111 {
112  return tuple_reduce_impl(std::forward<_Fn>(f),
113  f(std::forward<_Rs>(value), std::get<_I>(t)),
114  std::forward<_Tuple>(t),
115  std::index_sequence<_J...>());
116 }
117 
118 // Applies the function with the indexed elements of the tuple as
119 // arguments.
120 template <typename _Fn, class _Tuple, std::size_t... _I>
121 constexpr decltype(auto) tuple_apply_impl(_Fn&& f, _Tuple&& t,
122  std::index_sequence<_I...>)
123 {
124  return f(std::get<_I>(std::forward<_Tuple>(t))...);
125 }
126 
127 // Struct to wrap a function for self-reference.
128 template <typename _Fn>
129 struct self_ref_func
130 {
131  std::function<_Fn(self_ref_func)> fn;
132 };
133 
134 // Struct to wrap data, which may or may not be a reference.
135 template <typename _Tp,
136  bool _Deep_copy = std::is_rvalue_reference<_Tp>{} ||
137  (std::is_lvalue_reference<_Tp>{} &&
138  std::is_const<std::remove_reference_t<_Tp>>{})>
139 struct safe_wrapper
140 {
141  safe_wrapper(_Tp&& x) : value(std::forward<_Tp>(x)) {}
142  _Tp get() const { return value; }
143  _Tp value;
144 };
145 
146 // Partial specialization that copies the object used by the reference.
147 template <typename _Tp>
148 struct safe_wrapper<_Tp, true>
149 {
150  safe_wrapper(_Tp&& x) : value(std::forward<_Tp>(x)) {}
151  template <typename _Up = _Tp>
152  std::enable_if_t<std::is_rvalue_reference<_Up>{}, std::decay_t<_Tp>>
153  get() const
154  {
155  return value;
156  }
157  template <typename _Up = _Tp>
158  std::enable_if_t<!std::is_rvalue_reference<_Up>{}, _Tp>
159  get() const
160  {
161  return value;
162  }
163  std::decay_t<_Tp> value;
164 };
165 
166 // Declaration of curry, to be specialized below. The code is based on
167 // Julian Becker's StackOverflow answer at <url:http://tinyurl.com/cxx-curry>.
168 template <typename _Fn>
169 struct curry;
170 
171 // Termination of currying, which returns the original function.
172 template <typename _Rs, typename _Tp>
173 struct curry<std::function<_Rs(_Tp)>>
174 {
175  typedef std::function<_Rs(_Tp)> type;
176 
177  static type make(type f)
178  {
179  return f;
180  }
181 };
182 
183 // Recursion template to curry functions with more than one parameter.
184 template <typename _Rs, typename _Tp, typename... _Targs>
185 struct curry<std::function<_Rs(_Tp, _Targs...)>>
186 {
187  typedef typename curry<std::function<_Rs(_Targs...)>>::type remaining_type;
188  typedef std::function<remaining_type(_Tp)> type;
189 
190  static type make(std::function<_Rs(_Tp, _Targs...)> f)
191  {
192  return [f](_Tp&& x)
193  { // Use wrapper to ensure reference types are correctly captured.
194  return curry<std::function<_Rs(_Targs...)>>::make(
195  [f, w = safe_wrapper<_Tp>(std::forward<_Tp>(x))](
196  _Targs&&... args) -> decltype(auto)
197  {
198  return f(w.get(), std::forward<_Targs>(args)...);
199  });
200  };
201  }
202 };
203 
204 using std::begin;
205 using std::end;
206 
207 // Function declarations to resolve begin/end using argument-dependent lookup
208 template <class _Rng>
209 auto adl_begin(_Rng&& rng) -> decltype(begin(rng));
210 template <class _Rng>
211 auto adl_end(_Rng&& rng) -> decltype(end(rng));
212 
213 // Type alias to get the value type of a container or range
214 template <class _Rng>
215 using value_type = typename std::iterator_traits<decltype(
216  adl_begin(std::declval<_Rng>()))>::value_type;
217 
218 using std::swap;
219 
220 // Function declaration to resolve swap using argument-dependent lookup
221 template <typename _Tp>
222 void adl_swap(_Tp& lhs, _Tp& rhs) noexcept(noexcept(swap(lhs, rhs)));
223 
224 } /* namespace detail */
225 
227 class bad_optional_access : public std::logic_error
228 {
229 public:
231  : std::logic_error("optional has no valid value now") {}
232 };
233 
241 template <typename _Tp>
242 class optional
243 {
244 public:
245  static_assert(std::is_nothrow_destructible<_Tp>::value,
246  "optional type must be nothrow destructible");
247 
248  optional() noexcept : _M_pointer(nullptr) {}
249  optional(const optional& rhs)
250  {
251  if (rhs._M_pointer)
252  _M_pointer = new(_M_value) _Tp(*rhs);
253  else
254  _M_pointer = nullptr;
255  }
256  optional(optional&& rhs) noexcept(
257  std::is_nothrow_move_constructible<_Tp>::value)
258  {
259  if (rhs._M_pointer)
260  _M_pointer = new(_M_value) _Tp(std::move(*rhs));
261  else
262  _M_pointer = nullptr;
263  }
264  optional(const _Tp& x)
265  {
266  _M_pointer = new(_M_value) _Tp(x);
267  }
268  optional(_Tp&& x) noexcept(
269  std::is_nothrow_move_constructible<_Tp>::value)
270  {
271  _M_pointer = new(_M_value) _Tp(std::move(x));
272  }
273  ~optional() noexcept
274  {
275  if (_M_pointer)
276  destroy(_M_pointer);
277  }
278 
279  optional& operator=(const optional& rhs)
280  {
281  if (has_value() && rhs.has_value())
282  *_M_pointer = *rhs._M_pointer;
283  else
284  {
285  optional temp(rhs);
286  swap(temp);
287  }
288  return *this;
289  }
290  optional& operator=(optional&& rhs) noexcept(
291  std::is_nothrow_move_assignable<_Tp>::value &&
292  std::is_nothrow_move_constructible<_Tp>::value)
293  {
294  if (has_value() && rhs.has_value())
295  *_M_pointer = std::move(*rhs._M_pointer);
296  else
297  {
298  optional temp(std::move(rhs));
299  swap(temp);
300  }
301  return *this;
302  }
303 
304  constexpr _Tp* operator->()
305  {
306  return _M_pointer;
307  }
308  constexpr const _Tp* operator->() const
309  {
310  return _M_pointer;
311  }
312  constexpr _Tp& operator*() &
313  {
314  return *_M_pointer;
315  }
316  constexpr const _Tp& operator*() const&
317  {
318  return *_M_pointer;
319  }
320  constexpr _Tp&& operator*() &&
321  {
322  return std::move(*_M_pointer);
323  }
324 
325  bool has_value() const noexcept { return _M_pointer != nullptr; }
326 
327  _Tp& value() &
328  {
329  if (!_M_pointer)
330  throw bad_optional_access();
331  return *_M_pointer;
332  }
333  const _Tp& value() const&
334  {
335  if (!_M_pointer)
336  throw bad_optional_access();
337  return *_M_pointer;
338  }
339  _Tp&& value() &&
340  {
341  if (!_M_pointer)
342  throw bad_optional_access();
343  return std::move(*_M_pointer);
344  }
345 
346  template <typename _Up>
347  _Tp value_or(_Up&& default_value) const&
348  {
349  if (_M_pointer)
350  return operator*();
351  else
352  return default_value;
353  }
354  template <typename _Up>
355  _Tp value_or(_Up&& default_value) &&
356  {
357  if (_M_pointer)
358  return operator*();
359  else
360  return default_value;
361  }
362 
363  void reset() noexcept
364  {
365  if (_M_pointer)
366  {
367  destroy(_M_pointer);
368  _M_pointer = nullptr;
369  }
370  }
371  void swap(optional& rhs) noexcept(
372  std::is_nothrow_move_constructible<_Tp>::value &&
373  noexcept(detail::adl_swap(std::declval<_Tp&>(),
374  std::declval<_Tp&>())))
375  {
376  using std::swap;
377  if (has_value())
378  {
379  if (rhs.has_value())
380  swap(*_M_pointer, *rhs);
381  else
382  {
383  rhs._M_pointer =
384  new (rhs._M_value) _Tp(std::move(*_M_pointer));
385  reset();
386  }
387  }
388  else
389  {
390  if (rhs.has_value())
391  {
392  _M_pointer = new(_M_value) _Tp(std::move(*rhs));
393  rhs.reset();
394  }
395  }
396  }
397  template <typename... _Targs>
398  void emplace(_Targs&&... args)
399  {
400  reset();
401  _M_pointer = new(_M_value) _Tp(args...);
402  }
403 
404 private:
405  void destroy(_Tp* ptr) noexcept
406  {
407  _M_destroy(ptr, std::is_trivially_destructible<_Tp>());
408  }
409  void _M_destroy(_Tp*, std::true_type)
410  {}
411  void _M_destroy(_Tp* ptr, std::false_type)
412  {
413  ptr->~_Tp();
414  }
415 
416  _Tp* _M_pointer;
417  char _M_value[sizeof(_Tp)];
418 };
419 
420 template <typename _Tp>
421 constexpr optional<std::decay_t<_Tp>> make_optional(_Tp&& x)
422 {
423  return optional<std::decay_t<_Tp>>(std::forward<_Tp>(x));
424 }
425 
426 template <typename _Tp>
427 constexpr bool has_value(const optional<_Tp>& x) noexcept
428 {
429  return x.has_value();
430 }
431 
432 template <typename _Tp, typename... _Targs>
433 constexpr bool has_value(const optional<_Tp>& first,
434  const optional<_Targs>&... other) noexcept
435 {
436  return first.has_value() && has_value(other...);
437 }
438 
439 template <typename _Tp>
440 void swap(optional<_Tp>& lhs,
441  optional<_Tp>& rhs) noexcept(noexcept(lhs.swap(rhs)))
442 {
443  lhs.swap(rhs);
444 }
445 
452 template <typename _Fn>
453 auto lift_optional(_Fn&& f)
454 {
455  return [f = std::forward<_Fn>(f)](auto&&... args)
456  {
457  typedef std::decay_t<decltype(
458  f(std::forward<decltype(args)>(args).value()...))>
459  result_type;
460  if (has_value(args...))
461  return optional<result_type>(
462  f(std::forward<decltype(args)>(args).value()...));
463  else
464  return optional<result_type>();
465  };
466 }
467 
478 template <typename _Fn, typename... _Opt>
479 constexpr auto apply(_Fn&& f, _Opt&&... args) -> decltype(
480  has_value(args...),
481  optional<
482  std::decay_t<decltype(f(std::forward<_Opt>(args).value()...))>>())
483 {
484  typedef std::decay_t<decltype(f(std::forward<_Opt>(args).value()...))>
485  result_type;
486  if (has_value(args...))
487  return optional<result_type>(
488  f(std::forward<_Opt>(args).value()...));
489  else
490  return optional<result_type>();
491 }
492 
501 template <typename _Fn, class _Tuple>
502 constexpr auto apply(_Fn&& f, _Tuple&& t)
503  -> decltype(detail::tuple_apply_impl(
504  std::forward<_Fn>(f),
505  std::forward<_Tuple>(t),
506  std::make_index_sequence<
507  std::tuple_size<std::decay_t<_Tuple>>::value>()))
508 {
509  return detail::tuple_apply_impl(
510  std::forward<_Fn>(f),
511  std::forward<_Tuple>(t),
512  std::make_index_sequence<
513  std::tuple_size<std::decay_t<_Tuple>>::value>());
514 }
515 
524 template <typename _Fn, typename _T1, typename _T2>
525 constexpr auto fmap(_Fn&& f, const std::pair<_T1, _T2>& args)
526 {
527  return std::make_pair(f(args.first), f(args.second));
528 }
529 
538 template <typename _Fn, typename... _Targs>
539 constexpr auto fmap(_Fn&& f, const std::tuple<_Targs...>& args)
540 {
541  return detail::tuple_fmap_impl(std::forward<_Fn>(f), args,
542  std::index_sequence_for<_Targs...>());
543 }
544 
559 template <template <typename, typename> class _OutCont = std::vector,
560  template <typename> class _Alloc = std::allocator,
561  typename _Fn, class _Rng>
562 constexpr auto fmap(_Fn&& f, _Rng&& inputs) -> decltype(
563  detail::adl_begin(inputs), detail::adl_end(inputs),
564  _OutCont<
565  std::decay_t<decltype(f(*detail::adl_begin(inputs)))>,
566  _Alloc<std::decay_t<decltype(f(*detail::adl_begin(inputs)))>>>())
567 {
568  typedef std::decay_t<decltype(f(*detail::adl_begin(inputs)))>
569  result_type;
570  _OutCont<result_type, _Alloc<result_type>> result;
571  detail::try_reserve(
572  result, inputs,
573  std::integral_constant<
574  bool, detail::can_reserve<decltype(result), _Rng>::value>());
575  for (auto& item : inputs)
576  result.push_back(f(item));
577  return result;
578 }
579 
589 template <typename _Rs, typename _Fn, typename... _Targs>
590 constexpr auto reduce(_Fn&& f,
591  const std::tuple<_Targs...>& args,
592  _Rs&& value)
593 {
594  return detail::tuple_reduce_impl(std::forward<_Fn>(f),
595  std::forward<_Rs>(value),
596  args,
597  std::index_sequence_for<_Targs...>());
598 }
599 
612 template <typename _Fn, class _Rng>
613 constexpr auto reduce(_Fn&& f, _Rng&& inputs)
614 {
615  auto result = typename detail::value_type<_Rng>();
616  for (auto& item : inputs)
617  result = f(result, item);
618  return result;
619 }
620 
637 template <typename _Rs, typename _Fn, typename _Iter>
638 constexpr _Rs&& reduce(_Fn&& f, _Rs&& value, _Iter begin, _Iter end)
639 {
640  // Recursion (instead of iteration) is used in this function, as
641  // _Rs may be a reference type and a result of this type cannot
642  // be assigned to (like the implementation of reduce above).
643  if (begin == end)
644  return std::forward<_Rs>(value);
645  _Iter current = begin;
646  decltype(auto) reduced_once = f(std::forward<_Rs>(value), *current);
647  return reduce(std::forward<_Fn>(f), reduced_once, ++begin, end);
648 }
649 
675 template <typename _Rs, typename _Fn, class _Rng>
676 constexpr auto reduce(_Fn&& f, _Rng&& inputs, _Rs&& initval)
677  -> decltype(f(initval, *detail::adl_begin(inputs)))
678 {
679  using std::begin;
680  using std::end;
681  return reduce(std::forward<_Fn>(f), std::forward<_Rs>(initval),
682  begin(inputs), end(inputs));
683 }
684 
691 template <typename _T1, typename _T2, typename _Fn>
692 constexpr auto wrap_args_as_pair(_Fn&& f)
693 {
694  return [f = std::forward<_Fn>(f)](const std::pair<_T1, _T2>& arg)
695  -> decltype(auto)
696  {
697  return f(arg.first, arg.second);
698  };
699 }
700 
709 template <typename _Tuple, typename _Fn>
710 constexpr auto wrap_args_as_tuple(_Fn&& f)
711 {
712  return [f = std::forward<_Fn>(f)](_Tuple&& t) -> decltype(auto)
713  {
714  return apply(f, std::forward<_Tuple>(t));
715  };
716 }
717 
721 template <typename _Tp>
722 constexpr _Tp pipeline(_Tp&& data)
723 {
724  return std::forward<_Tp>(data);
725 }
726 
734 template <typename _Tp, typename _Fn, typename... _Fargs>
735 constexpr decltype(auto) pipeline(_Tp&& data, _Fn&& f, _Fargs&&... args)
736 {
737  return pipeline(f(std::forward<_Tp>(data)),
738  std::forward<_Fargs>(args)...);
739 }
740 
746 auto compose()
747 {
748  return [](auto&& x) -> decltype(auto)
749  {
750  return std::forward<decltype(x)>(x);
751  };
752 }
753 
760 template <typename _Fn>
761 auto compose(_Fn f)
762 {
763  return [f](auto&&... x) -> decltype(auto)
764  {
765  return f(std::forward<decltype(x)>(x)...);
766  };
767 }
768 
776 template <typename _Fn, typename... _Fargs>
777 auto compose(_Fn f, _Fargs... args)
778 {
779  return [f, args...](auto&&... x) -> decltype(auto)
780  {
781  return f(compose(args...)(std::forward<decltype(x)>(x)...));
782  };
783 }
784 
792 template <typename _Rs, typename _Tp>
793 std::function<_Rs(_Tp)> fix_simple(
794  std::function<_Rs(std::function<_Rs(_Tp)>, _Tp)> f)
795 { // Y f = f (λx.(Y f) x)
796  return [f](_Tp&& x)
797  {
798  return f([f](_Tp&& x)
799  {
800  return fix_simple(f)(std::forward<_Tp>(x));
801  },
802  std::forward<_Tp>(x));
803  };
804 }
805 
813 template <typename _Rs, typename _Tp>
814 std::function<_Rs(_Tp)> fix_simple(
815  std::function<std::function<_Rs(_Tp)>(std::function<_Rs(_Tp)>)> f)
816 { // Y f = f (λx.(Y f) x)
817  return f([f](_Tp&& x)
818  {
819  return fix_simple(f)(std::forward<_Tp>(x));
820  });
821 }
822 
830 template <typename _Rs, typename _Tp>
831 std::function<_Rs(_Tp)> fix_curry(
832  std::function<std::function<_Rs(_Tp)>(std::function<_Rs(_Tp)>)> f)
833 { // Y = λf.(λx.x x) (λx.f (λy.(x x) y))
834  typedef std::function<_Rs(_Tp)> fn_1st_ord;
835  typedef detail::self_ref_func<fn_1st_ord> fn_self_ref;
836 
837  fn_self_ref r = {
838  [f](fn_self_ref x)
839  { // λx.f (λy.(x x) y)
840  return f(fn_1st_ord([x](_Tp&& y)
841  {
842  return x.fn(x)(std::forward<_Tp>(y));
843  }));
844  }
845  };
846  return r.fn(r);
847 }
848 
859 template <typename _Rs, typename... _Targs>
860 auto make_curry(std::function<_Rs(_Targs...)> f)
861 {
862  return detail::curry<std::function<_Rs(_Targs...)>>::make(std::move(f));
863 }
864 
875 template <typename _Rs, typename... _Targs>
876 auto make_curry(_Rs(*f)(_Targs...))
877 {
878  return detail::curry<std::function<_Rs(_Targs...)>>::make(f);
879 }
880 
892 template <typename _FnType, typename _Fn>
893 auto make_curry(_Fn&& f)
894 {
895  return detail::curry<std::function<_FnType>>::make(
896  std::forward<_Fn>(f));
897 }
898 
899 NVWA_NAMESPACE_END
900 
901 #endif // NVWA_FUNCTIONAL_H
constexpr auto wrap_args_as_pair(_Fn &&f)
Makes a two-argument function accept a pair instead.
Definition: functional.h:692
Class for optional values.
Definition: functional.h:242
void swap(bool_array &lhs, bool_array &rhs) noexcept
Exchanges the content of two bool_arrays.
Definition: bool_array.h:358
constexpr auto fmap(_Fn &&f, _Rng &&inputs) -> decltype(detail::adl_begin(inputs), detail::adl_end(inputs), _OutCont< std::decay_t< decltype(f(*detail::adl_begin(inputs)))>, _Alloc< std::decay_t< decltype(f(*detail::adl_begin(inputs)))>>>())
Applies a function to each element in the input range.
Definition: functional.h:562
std::function< _Rs(_Tp)> fix_curry(std::function< std::function< _Rs(_Tp)>(std::function< _Rs(_Tp)>)> f)
Generates the fixed point using the Curry-style fixed-point combinator.
Definition: functional.h:831
Class for bad optional access exception.
Definition: functional.h:227
constexpr auto reduce(_Fn &&f, _Rng &&inputs, _Rs &&initval) -> decltype(f(initval, *detail::adl_begin(inputs)))
Applies a function cumulatively to elements in the input range.
Definition: functional.h:676
std::function< _Rs(_Tp)> fix_simple(std::function< std::function< _Rs(_Tp)>(std::function< _Rs(_Tp)>)> f)
Generates the fixed point using the simple fixed-point combinator.
Definition: functional.h:814
auto compose(_Fn f, _Fargs... args)
Constructs a function (object) that composes the passed functions.
Definition: functional.h:777
constexpr auto wrap_args_as_tuple(_Fn &&f)
Makes a function accept a tuple as its arguments.
Definition: functional.h:710
decltype(auto) constexpr pipeline(_Tp &&data, _Fn &&f, _Fargs &&... args)
Applies the functions in the arguments to the data consecutively.
Definition: functional.h:735
constexpr auto apply(_Fn &&f, _Tuple &&t) -> decltype(detail::tuple_apply_impl(std::forward< _Fn >(f), std::forward< _Tuple >(t), std::make_index_sequence< std::tuple_size< std::decay_t< _Tuple >>::value >()))
Applies the function with all elements of the typle as arguments.
Definition: functional.h:502
auto make_curry(_Fn &&f)
Makes a curried function.
Definition: functional.h:893
auto lift_optional(_Fn &&f)
Lifts a function so that it takes optionals and returns an optional.
Definition: functional.h:453
Common definitions for preprocessing.