You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在C++中实现Haskell风格Functor Concept的问题与改进咨询

基于Haskell Functor的C++ Concept实现问题

初始尝试与问题

近期我尝试基于Haskell的Functor在C++中创建对应的Concept,初始代码如下:

template <template<class>class F>
concept Functor = requires (F<A> f) {
    { fmap(function, f) } -> std::same_as<F<decltype(function(std::declval<A>))>>;
};

该代码存在function与A类型的依赖问题:若将它们加入模板声明,Functor Concept将不仅依赖实际的函子F,还会依赖这两个类型。我想知道这类需求在C++中是否可行,同时希望让已定义fmap的static_assert(Functor<std::optional<int>>)能够编译通过。

补充说明

因评论区存在误解,特此澄清:本文所指Functor为Haskell中的函子,即实现如下函数的类型:

fmap :: Functor f => (a -> b) -> f a -> f b

而非C++中重载operator()的类型。可将其理解为无需手动解包即可将std::optional<int>转换为std::optional<std::string>的方法。

可行方案

目前我已取得一定进展,写出了如下代码:

template <template<class, class...> class F, class T>
struct Functor {
    template <class Callable>
    [[nodiscard]] static constexpr auto
    fmap(Callable callable, F<T>&& f) -> F<std::decay_t<decltype(callable(std::declval<T>))>>;
};

template <template<class, class...> typename F, class T>
concept FunctorConcept = requires (F<T>&& f) {
    { Functor<F, T>::fmap(std::identity{}, std::forward<F<T>>(f)) } -> std::same_as<F<std::decay_t<decltype(std::identity{}(std::declval<T>))>>>;
};

template <class T>
struct Functor<std::optional, T> {
    template <class Callable>
    [[nodiscard]] constexpr static auto
    fmap(Callable callable, std::optional<T>&& f) -> std::optional<std::decay_t<decltype(callable(std::declval<T>))>> {
        if (f)
            return callable(*std::forward<std::optional<T>>(f));
        return std::nullopt;
    }
};

template <class T>
struct Functor<std::vector, T> {

    template <class Callable>
    [[nodiscard]] constexpr static auto
    fmap(Callable callable, std::vector<T>&& f) -> std::vector<std::decay_t<decltype(callable(std::declval<T>))>> {
        std::vector<std::decay_t<decltype(callable(std::declval<T>))>> result;
        std::transform(begin(std::forward<std::vector<T>>(f)), end(std::forward<std::vector<T>>(f)), std::back_inserter(result), callable);
        return result;
    }
};


int main() {

    static_assert(FunctorConcept<std::optional, int>);
    static_assert(FunctorConcept<std::optional, float>);
    static_assert(FunctorConcept<std::vector, float>);

    return 0;
}

我通过独立结构体处理fmap重载,仅用std::identity验证Concept,但仍对std::identity的使用方式不满意,同时担忧fmap定义的返回类型与Concept不一致易导致代码出错,特此咨询这两点的改进方案。


内容的提问来源于stack exchange,提问作者Dragomir

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 21:01:11