Home > Blockchain >  Implementing Functor concept in C
Implementing Functor concept in C

Time:12-21

Recently I've been trying to create a C concept around Haskell's Functor. Something like this:

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

The problem is with function and A type. If I put them in template declaration than Functor concept depends on them not only on the actual functor F.

Is this sort of thing even possible in C .

I wish to make this code compile: static_assert(Functor<std::optional<int>) where I already defined fmap on optional.

CodePudding user response:

Currently, as far as I see, that is not possible in the generality that you seek. The reason is that the all-quantifier over type arguments is not sensible in C because there will always be a lot of types/function combination for which a given template does not represent a Functor:

  • function: []{}. std::optional<void> is not instantiatable.
  • type: void. Similar problem: std::optional is not a Functor for that.
  • type: int&. std::optional is not a Functor because std::optional<int&> does not exist.

Here is an approximation that illustrates the problem:

#include <concepts>
#include <optional>

template <typename T>
inline auto fmap(auto f, std::optional<T> opt)
    -> std::optional<decltype(f(std::declval<T>()))> {
  if (opt) return f(*opt);
  return std::nullopt;
}

template <template <typename> typename F, typename T>
concept Functor = requires (F<T> f) {
    { fmap([](auto) {return nullptr;}, f) } -> std::same_as<F<decltype(nullptr)>>;
};

Here, the input function is fixed to a lambda that always maps to nullptr. The type for which the template shall be a Functor must be passed, so this:

static_assert(Functor<std::optional,int>);

passes, but this:

static_assert(Functor<std::optional,int&>);

does not.

Of course, this is unsatisfying because even if the fmap defined for std::optional works on [](auto) {return nullptr;} it doesn't mean it will work on the next function.

  • Related