Skip to content

Instantly share code, notes, and snippets.

@d-plaindoux
Last active December 8, 2020 08:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save d-plaindoux/22b5140f35cda7701e23d13436af1e4c to your computer and use it in GitHub Desktop.
Save d-plaindoux/22b5140f35cda7701e23d13436af1e4c to your computer and use it in GitHub Desktop.
// See https://stackoverflow.com/questions/2565097/higher-kinded-types-with-c
template<typename a, typename b>
using Function = b (*)(const a &);
template<template<typename> class m>
struct Functor {
template<typename a, typename b>
static m<b> map(const m<a> &, Function<a, b>);
};
template<template<typename> class m>
struct Applicative {
template<typename a>
static m<a> pure(const a &);
template<typename a, typename b>
static m<b> apply(const m<Function<a, b>> &, const m<a> &);
};
template<template<typename> class m>
struct Monad {
template<typename a>
static m<a> returns(const a &);
template<typename a>
static m<a> join(const m<m<a>> &ma);
template<typename a, typename b>
static m<b> bind(const m<a> &, Function<a, m<b>>);
};
// Maybe data structure definition ....
template<typename a>
struct Maybe {
bool isEmpty;
a value;
static Maybe<a> empty() {
Maybe<a> x{};
x.isEmpty = true;
return x;
}
static Maybe<a> some(a value) {
Maybe<a> x{};
x.isEmpty = false;
x.value = value;
return x;
}
};
template<>
struct Functor<Maybe> {
template<typename a, typename b>
static Maybe<b> map(const Maybe<a> &ma, Function<a, b> f) {
if (ma.isEmpty)
return Maybe<b>::empty();
else
return Maybe<b>::some(f(ma.value));
}
};
template<>
struct Applicative<Maybe> : Functor<Maybe> {
template<typename a>
static Maybe<a> pure(const a &v) {
return Maybe<a>::some(v);
}
template<typename a, typename b>
static Maybe<b> apply(const Maybe<Function<a, b>> &mf, const Maybe<a> &ma) {
if (mf.isEmpty)
return Maybe<b>::empty();
else
return map(ma, mf.value);
}
};
template<>
struct Monad<Maybe> : Applicative<Maybe> {
template<typename a>
static Maybe<a> returns(const a &v) {
return Applicative<Maybe>::pure(v);
}
template<typename a>
static Maybe<a> join(const Maybe<Maybe<a>> &ma) {
if (ma.isEmpty)
return Maybe<a>::empty();
else
return ma.value;
}
template<typename a, typename b>
static Maybe<b> bind(const Maybe<a> &ma, Function<a, Maybe<b>> f) {
return join(map(ma, f));
}
};
void example() {
auto ma = Monad<Maybe>::returns(1);
Function<int, Maybe<int>> f1 = [](auto a) { return Monad<Maybe>::returns(a + 1); };
auto mb = Monad<Maybe>::bind(ma, f1);
Function<int, int> f2 = [](auto c) { return c + 1; };
auto mc = Functor<Maybe>::map(mb, f2);
auto md = Applicative<Maybe>::apply(Applicative<Maybe>::pure(f1), mc);
// etc ...
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment