Created
June 21, 2019 08:19
-
-
Save plasma-effect/986f8e8fd105b2959b69d94bacbc0e64 to your computer and use it in GitHub Desktop.
Maybeモナドっぽい何か(お前はMaybeモナドを理解しているのか?)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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))...)); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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