Skip to content

Instantly share code, notes, and snippets.

@plasma-effect
Created June 21, 2019 08:19
Show Gist options
  • Save plasma-effect/986f8e8fd105b2959b69d94bacbc0e64 to your computer and use it in GitHub Desktop.
Save plasma-effect/986f8e8fd105b2959b69d94bacbc0e64 to your computer and use it in GitHub Desktop.
Maybeモナドっぽい何か(お前はMaybeモナドを理解しているのか?)
// copyright (c) 2019 plasma-effect
// Distributed under the Boost Software License, Version 1.0.
// (See http://www.boost.org/LICENSE_1_0.txt)
#pragma once
#include<optional>
#include<stdexcept>
#include<type_traits>
namespace maybe_monad
{
class optional_exception :public std::logic_error
{
public:
optional_exception() :logic_error("this function is not wrapped in maybe_monad::maybe")
{
}
};
namespace detail
{
template<class T>decltype(auto) unwrap(std::optional<T>& v)
{
if (v)
{
return *v;
}
else
{
throw optional_exception();
}
}
template<class T>decltype(auto) unwrap(std::optional<T>const& v)
{
if (v)
{
return *v;
}
else
{
throw optional_exception();
}
}
template<class T>decltype(auto) unwrap(std::optional<T>&& v)
{
if (v)
{
return std::move(*v);
}
else
{
throw optional_exception();
}
}
template<class T>decltype(auto) unwrap(T&& v)
{
return std::forward<T>(v);
}
template<class T>struct return_type
{
constexpr static std::optional<T> call(T&& v)
{
return std::make_optional(std::forward<T>(v));
}
};
template<class T>struct return_type<std::optional<T>>
{
constexpr static std::optional<T>&& call(std::optional<T>&& v)
{
return std::move(v);
}
constexpr static std::optional<T>const& call(std::optional<T>const& v)
{
return v;
}
};
template<class T>auto call_return(T&& v)
{
return return_type<T>::call(std::move(v));
}
template<class T>auto call_return(T const& v)
{
return return_type<T>::call(v);
}
}
struct maybe_t
{
template<class Func>struct callable
{
Func func;
template<class... Ts>auto operator()(Ts&& ...args)const
->decltype(detail::call_return(func(std::forward<Ts>(args)...)))
{
try
{
return detail::call_return(func(std::forward<Ts>(args)...));
}
catch (optional_exception)
{
return std::nullopt;
}
}
};
template<class Func>constexpr auto operator|(Func func)const
{
return callable<Func>{func};
}
};
constexpr maybe_t maybe;
template<class Func, class... Ts>auto call(Func func, Ts&& ... args)
{
return detail::call_return(func(detail::unwrap(std::forward<Ts>(args))...));
}
}
#include<iostream>
#include<functional>
#include"maybe.hpp"
using maybe_monad::maybe;
using maybe_monad::call;
void print(std::optional<int>const& v)
{
if (v)
{
std::cout << *v << std::endl;
}
else
{
std::cout << "None" << std::endl;
}
}
auto func = maybe | [](std::optional<int> x)
{
auto a = call(std::plus<>(), x, 2);
auto b = call([](int v)->std::optional<int>
{
if (v < 10)
{
return v;
}
else
{
return std::nullopt;
}
}, a);
return call([](auto&&)
{
return 1;
}, b);
};
int main()
{
print(func(0));
std::cout << std::endl;
print(func(10));
std::cout << std::endl;
print(func(std::nullopt));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment