如何解决如何在 Boost.Hana 中使 std::vector 成为 Applicative 而不先使其成为 Monad?
根据标题,我想了解如何使 std::vector
成为 applicative
而不是 Monad
(嗯,还没有)。这只是为了探索和理解 Boost.Hana 和函数式编程。
Functor
在 hana/ext/std/vector.hpp
中,Functor
的 std::vector
实例已被注释掉,但是,如果我取消注释它或将其复制到我的代码。
applicative
然而,那里没有代码使它成为 applicative
(反过来,也没有使它成为 Monad
),所以我研究了 compiler explorer 以了解必须实施什么才能自己做。它需要_impl
对ap
和lift
的实现。
-
关于
lift
,以下实现是否足够好?template <> struct lift_impl<ext::std::vector_tag> { template <typename T> static std::vector<std::decay_t<T>> apply(T&& value) { return {std::forward<T>(value)}; } };
另一方面,由于
hana/concept/applicative.hpp
包含Sequence
的默认实现,template <typename S> struct lift_impl<S,when<Sequence<S>::value>> { template <typename X> static constexpr decltype(auto) apply(X&& x) { return hana::make<S>(static_cast<X&&>(x)); } };
我也可以让
std::vector
变成Sequence
,这样更简单:template <> struct Sequence<ext::std::vector_tag> { static constexpr bool value = true; };
-
同样,
hana/lift.hpp
也有Sequences
的实现,但它使用hana::chain
,因此它假定Monad
实例在第一个地点。但是如果我想让
std::vector
成为applicative
而不是Monad
怎么办?我应该自己定制ap
。以下正确吗?template <> struct ap_impl<ext::std::vector_tag> { template<typename F,typename X,typename Y = std::decay_t<decltype((*std::declval<F>().begin())(*std::declval<X>().begin()))>> static constexpr std::vector<Y> apply(F&& f,X&& x) { std::vector<Y> result; result.reserve(f.size() * x.size()); for (auto const& f_ : f) { for (auto const& x_ : x) { result.emplace_back(f_(x_)); } } return result; } };
结果
乍一看我认为它有效,因为在这个简单的情况下(hana/ap.hpp
)它确实给出了正确的结果:
int main()
{
auto vplus = std::vector{std::plus<int>{}};
auto vec = hana::ap(
std::vector{std::plus<int>{}},// wrapping 1 object in a vector
std::vector<int>{10,20},std::vector<int>{1,2});
BOOST_HANA_RUNTIME_ASSERT(vec == std::vector<int>{11,12,21,22});
}
失望
但是我发现我的解决方案存在一些弱点:
- 我使用
std::vector
而不是lift
将 1 个函数包装成一个向量,我相信这看起来有点不习惯; - 一想到需要使用
std::vector
而不是lift
的情况,即当我想应用 1 个以上的函数时,我就反对这样一个事实,例如,我不能将std::plus
和std::minus
放在同一个向量中,因为它们是不同类型的函数对象。
对于 hana::tuple
(或者 std::tuple
,如果我为它定义了所需的实例),这是小菜一碟,因为它可以容纳异构类型:
// TUPLE EXAMPLE
auto tuple = hana::ap(
hana::make_tuple(std::plus<int>{},std::minus<>{}),hana::make_tuple(10,20),hana::make_tuple(1,2));
BOOST_HANA_RUNTIME_ASSERT(tuple == hana::make_tuple(11,22,9,8,19,18));
我的问题
有没有办法让 std::vector
变成 applicative
,使 // TUPLE EXAMPLE
对 std::vector
起作用?
可能需要 std::function
和/或类型擦除才能完成任务?
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。