mpc
Haskell-like feature supports in C++
identity.hpp
Go to the documentation of this file.
1
2#pragma once
3#include <functional> // std::invoke
6#include <mpc/prelude.hpp>
8
9namespace mpc {
10 // Identity
11 // https://hackage.haskell.org/package/base-4.16.0.0/docs/Data-Functor-Identity.html
12
14 template <copy_constructible_object T>
15 struct Identity {
16 private:
17 copyable_box<T> instance_{};
18
19 public:
20 using value_type = T;
21
22 constexpr Identity() //
23 noexcept(std::is_nothrow_default_constructible_v<T>) //
24 requires std::default_initializable<T> //
25 : instance_(std::in_place) {}
26
27 template <class U = T>
28 requires std::constructible_from<T, U&&>
29 constexpr explicit Identity(U&& u) //
30 noexcept(std::is_nothrow_constructible_v<T, U&&>)
31 : instance_(std::in_place, std::forward<U>(u)) {}
32
33 constexpr const T& operator*() const& noexcept {
34 return *instance_;
35 }
36 constexpr const T&& operator*() const&& noexcept {
37 return std::move(*instance_);
38 }
39 constexpr T& operator*() & noexcept {
40 return *instance_;
41 }
42 constexpr T&& operator*() && noexcept {
43 return std::move(*instance_);
44 }
45
46 constexpr const T* operator->() const noexcept {
47 return instance_.operator->();
48 }
49 constexpr T* operator->() noexcept {
50 return instance_.operator->();
51 }
52 };
53
54 template <class T>
56
57 namespace detail {
58 template <class>
59 struct is_Identity_impl : std::false_type {};
60
61 template <copy_constructible_object T>
62 struct is_Identity_impl<Identity<T>> : std::true_type {};
63 } // namespace detail
64
65 template <class T>
66 concept is_Identity = detail::is_Identity_impl<std::remove_cvref_t<T>>::value;
67
68 namespace detail {
70 template <copy_constructible_object U>
71 constexpr auto operator()(U&& u) const {
72 return Identity<std::decay_t<U>>(std::forward<U>(u));
73 }
74 };
75
77 template <is_Identity I>
78 constexpr auto operator()(I&& x) const noexcept -> decltype(*std::forward<I>(x)) {
79 return *std::forward<I>(x);
80 }
81 };
82 } // namespace detail
83
84 inline namespace cpo {
85 inline constexpr partial<detail::make_Identity_op> make_Identity{};
86
87 inline constexpr partial<detail::run_Identity_op> run_Identity{};
88 } // namespace cpo
89
90 // clang-format off
91
94 template <copy_constructible_object T>
97 struct bind_op {
98 template <is_Identity I, class F>
99 constexpr auto operator()(I&& x, F&& f) const
100 noexcept(noexcept(std::invoke(std::forward<F>(f), run_Identity % std::forward<I>(x))))
101 -> decltype( std::invoke(std::forward<F>(f), run_Identity % std::forward<I>(x))) {
102 return std::invoke(std::forward<F>(f), run_Identity % std::forward<I>(x));
103 }
104 };
105
106 static constexpr bind_op bind{};
107 };
108
109 template <copy_constructible_object T>
111 // fmap :: (a -> b) -> f a -> f b
112 struct fmap_op {
113 template <class F, is_Identity I>
114 constexpr auto operator()(F&& f, I&& x) const
115 noexcept(noexcept(make_Identity(std::invoke(std::forward<F>(f), run_Identity % std::forward<I>(x)))))
116 -> decltype( make_Identity(std::invoke(std::forward<F>(f), run_Identity % std::forward<I>(x)))) {
117 return make_Identity(std::invoke(std::forward<F>(f), run_Identity % std::forward<I>(x)));
118 }
119 };
120
121 static constexpr fmap_op fmap{};
122 static constexpr auto replace2nd = functors::replace2nd;
123 };
124
125 template <copy_constructible_object T>
127 static constexpr auto pure = make_Identity;
128 static constexpr auto seq_apply = monads::seq_apply;
129 static constexpr auto liftA2 = applicatives::liftA2;
130 static constexpr auto discard2nd = applicatives::discard2nd;
131 static constexpr auto discard1st = monads::discard1st;
132 };
133 // clang-format on
134} // namespace mpc
A partial specialization of copyable_box.
Definition: copyable_box.hpp:124
constexpr partial< detail::liftA2_op > liftA2
liftA2 :: (a -> b -> c) -> f a -> f b -> f c
Definition: applicative.hpp:173
constexpr auto discard2nd
discard2nd :: f a -> f b -> f a
Definition: applicative.hpp:182
constexpr partial< detail::fmap_op > fmap
fmap :: (a -> b) -> f a -> f b
Definition: applicative.hpp:161
constexpr partial< detail::liftA2_op > liftA2
liftA2 :: (a -> b -> c) -> f a -> f b -> f c
Definition: applicative.hpp:102
constexpr partial< detail::bind_op > bind
bind :: forall a b. m a -> (a -> m b) -> m b
Definition: monad.hpp:45
constexpr partial< detail::discard1st_op > discard1st
discard1st :: f a -> f b -> f b
Definition: applicative.hpp:108
constexpr partial< detail::replace2nd_op > replace2nd
replace2nd :: a -> f b -> f a
Definition: functor.hpp:53
constexpr partial< detail::discard2nd_op > discard2nd
discard2nd :: f a -> f b -> f a
Definition: applicative.hpp:105
constexpr partial< detail::seq_apply_op > seq_apply
seq_apply :: f (a -> b) -> f a -> f b
Definition: applicative.hpp:99
constexpr partial< detail::pure_op< F > > pure
pure :: a -> f a
Definition: applicative.hpp:96
constexpr auto replace2nd
replace2nd :: a -> f b -> f a
Definition: functor.hpp:65
constexpr partial< detail::discard1st_op > discard1st
discard1st :: f a -> f b -> f b
Definition: monad.hpp:109
constexpr partial< detail::seq_apply_op > seq_apply
seq_apply :: f (a -> b) -> f a -> f b
Definition: monad.hpp:106
newtype Identity a = Identity { runIdentity :: a }
Definition: identity.hpp:15
class Functor f => Applicative f where
Definition: applicative.hpp:18
Definition: identity.hpp:59
Definition: identity.hpp:69
Definition: identity.hpp:76
class Functor f where
Definition: functor.hpp:14
class Applicative m => Monad m where
Definition: monad.hpp:15
Implements a perfect-forwarding call wrapper.
Definition: partial.hpp:63