mpc
Haskell-like feature supports in C++
list.hpp
Go to the documentation of this file.
1
2#pragma once
3#include <algorithm> // std::transform
4#include <functional> // std::invoke
5#include <iterator>
6#include <list>
9#include <mpc/data/maybe.hpp>
11#include <mpc/prelude.hpp> // identity
12#include <mpc/ranges.hpp>
13
14namespace mpc {
15 // List operations
16 // https://hackage.haskell.org/package/base-4.17.0.0/docs/Prelude.html#g:13
17
18 namespace detail {
19 template <class>
20 struct is_list_impl : std::false_type {};
21
22 template <class T, class Alloc>
23 struct is_list_impl<std::list<T, Alloc>> : std::true_type {};
24 } // namespace detail
25
26 template <class T>
27 concept is_list = detail::is_list_impl<std::remove_cvref_t<T>>::value;
28
29 // cons, foldr
30 namespace detail {
31 struct cons_op {
32 template <class T, is_list L>
33 constexpr auto operator()(T&& t, L&& l) const {
34 auto ret = std::forward<L>(l);
35 ret.emplace_front(std::forward<T>(t));
36 return ret;
37 }
38 };
39
40 struct uncons_op {
41 template <is_list L>
42 constexpr auto operator()(L&& l) const
43 -> maybe<std::pair<mpc::ranges::range_value_t<L>, std::remove_cvref_t<L>>> {
44 if (l.empty()) {
45 return nothing;
46 } else {
47 auto tail = std::forward<L>(l);
48 auto head = std::move(tail.front());
49 tail.pop_front();
50 return make_just(std::make_pair(std::move(head), std::move(tail)));
51 }
52 }
53 };
54
55 struct append_op {
56 template <is_list L1, is_list L2>
57 constexpr auto operator()(L1&& l1, L2&& l2) const {
58 auto head = std::forward<L1>(l1);
59 auto tail = std::forward<L2>(l2);
60 head.splice(head.end(), std::move(tail));
61 return head;
62 }
63 };
64
65 struct foldr_op {
66 template <class Fn, std::movable T, std::input_iterator I, std::sentinel_for<I> S>
67 constexpr auto operator()(Fn op, T&& init, I first, S last) const -> T {
68 if (first == last) {
69 return std::forward<T>(init);
70 } else {
71 auto tmp = first++;
72 return std::invoke(op, *tmp, this->operator()(op, std::forward<T>(init), first, last));
73 }
74 }
75
76 template <class Fn, std::movable T, mpc::ranges::input_range R>
77 constexpr auto operator()(Fn&& op, T&& init, R&& r) const -> T {
78 return this->operator()(std::forward<Fn>(op), std::forward<T>(init), mpc::ranges::begin(r),
79 mpc::ranges::end(r));
80 }
81 };
82 } // namespace detail
83
84 inline namespace cpo {
85 inline constexpr partial<detail::cons_op> cons;
86
87 inline constexpr partial<detail::uncons_op> uncons;
88
89 inline constexpr partial<detail::append_op> append;
90
91 inline constexpr partial<detail::foldr_op> foldr;
92 } // namespace cpo
93
94 // instances
95 template <class T>
96 struct functor_traits<std::list<T>> {
97 struct fmap_op {
98 template <class Fn, is_list L>
99 constexpr auto operator()(Fn f, L&& l) const {
100 using U = std::remove_cvref_t<std::invoke_result_t<Fn&, mpc::ranges::range_reference_t<L>>>;
101 std::list<U> ret(l.size());
102 std::transform(l.begin(), l.end(), ret.begin(), std::move(f));
103 return ret;
104 }
105 };
106
107 static constexpr fmap_op fmap{};
108 static constexpr auto replace2nd = functors::replace2nd;
109 };
110
111 template <class T>
112 struct applicative_traits<std::list<T>> {
113 struct pure_op {
114 template <class U>
115 constexpr auto operator()(U&& u) const {
116 return std::list{std::forward<U>(u)};
117 }
118 };
119
120 struct liftA2_op {
121 template <class Fn, is_list L1, is_list L2>
122 constexpr auto operator()(Fn f, L1&& l1, L2&& l2) const {
123 using U = std::remove_cvref_t<std::invoke_result_t<Fn&, mpc::ranges::range_reference_t<L1>,
124 mpc::ranges::range_reference_t<L2>>>;
125 const auto n = std::min(l1.size(), l2.size());
126 std::list<U> ret(n);
127 std::transform(l1.begin(), l1.end(), l2.begin(), l2.end(), ret.begin(), std::move(f));
128 return ret;
129 }
130 };
131
132 static constexpr pure_op pure{};
133 static constexpr liftA2_op liftA2{};
134 static constexpr auto seq_apply = applicatives::seq_apply;
135 static constexpr auto discard2nd = applicatives::discard2nd;
136 static constexpr auto discard1st = applicatives::discard1st;
137 };
138
139 // sequence
140 // https://hackage.haskell.org/package/base-4.17.0.0/docs/src/Data.Traversable.html#traverse
141 // https://hackage.haskell.org/package/base-4.17.0.0/docs/src/Data.Traversable.html#Traversable
142 // traverse :: Applicative f => (a -> f b) -> t a -> f (t b)
143 // traverse f = sequenceA . fmap f
144 //
145 // sequenceA :: Applicative f => t (f a) -> f (t a)
146 // sequenceA = traverse id
147 //
148 // instance Traversable [] where
149 // traverse f = List.foldr cons_f (pure [])
150 // where cons_f x ys = liftA2 (:) (f x) ys
151 namespace detail {
152 struct sequence_op {
153 // FIXME: 本来 applicative T
154 template <monad T>
155 constexpr auto operator()(const std::list<T>& l) const {
156 // FIXME: 不正な方法で monad の value_type を取得している
157 using U = holding_or_t<T, std::remove_cvref_t<decltype(mpc::bind(l.front(), identity))>>;
158 return foldr(mpc::liftA2 % cons, mpc::returns<T> % std::list<U>{}, l);
159 }
160 };
161 } // namespace detail
162
163 inline namespace cpo {
164 inline constexpr partial<detail::sequence_op> sequence;
165 } // namespace cpo
166} // namespace mpc
std::variant< nothing_t, just_t< T > > maybe
data Maybe a = Nothing | Just a
Definition: maybe.hpp:33
constexpr auto discard1st
discard1st :: f a -> f b -> f b
Definition: applicative.hpp:191
constexpr auto seq_apply
seq_apply :: f (a -> b) -> f a -> f b
Definition: applicative.hpp:170
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::replace2nd_op > replace2nd
replace2nd :: a -> f b -> f a
Definition: functor.hpp:53
constexpr partial< std::identity > identity
Identity mapping.
Definition: identity.hpp:11
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
class Functor f => Applicative f where
Definition: applicative.hpp:18
Definition: list.hpp:55
Definition: list.hpp:31
Definition: list.hpp:65
Definition: list.hpp:20
Definition: list.hpp:152
Definition: list.hpp:40
class Functor f where
Definition: functor.hpp:14
Implements a perfect-forwarding call wrapper.
Definition: partial.hpp:63