|
// Copyright 2014 Samplecount S.L. |
|
// |
|
// Licensed under the Apache License, Version 2.0 (the "License"); |
|
// you may not use this file except in compliance with the License. |
|
// You may obtain a copy of the License at |
|
// |
|
// http://www.apache.org/licenses/LICENSE-2.0 |
|
// |
|
// Unless required by applicable law or agreed to in writing, software |
|
// distributed under the License is distributed on an "AS IS" BASIS, |
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
// See the License for the specific language governing permissions and |
|
// limitations under the License. |
|
|
|
#ifndef HEARHEARME_CONT_HPP_INCLUDED |
|
#define HEARHEARME_CONT_HPP_INCLUDED |
|
|
|
#include <boost/variant.hpp> |
|
|
|
#include <exception> |
|
#include <functional> |
|
#include <list> |
|
#include <string> |
|
#include <tuple> |
|
|
|
namespace HearHearMe { |
|
|
|
template <typename A> using Result = boost::variant<std::exception_ptr,A>; |
|
|
|
template <typename R, typename A> using Cont = std::function<R(std::function<R(Result<A>)>)>; |
|
|
|
template <typename R, typename A> |
|
Cont<R,A> pure(A x) |
|
{ |
|
return [=](std::function<R(Result<A>)> k){ |
|
return k(Result<A>(x)); |
|
}; |
|
} |
|
|
|
struct Void {}; |
|
|
|
template <typename R> |
|
Cont<R,Void> pure() |
|
{ |
|
return [](std::function<R(Void)> k){ |
|
return k(Void()); |
|
}; |
|
} |
|
|
|
template <typename R, typename A> |
|
Cont<R,A> fail(std::exception_ptr eptr) |
|
{ |
|
return [=](std::function<R(Result<A>)> k) { |
|
return k(Result<A>(eptr)); |
|
}; |
|
} |
|
|
|
template <typename R, typename A> |
|
Cont<R,A> fail(std::string msg) |
|
{ |
|
return [=](std::function<R(Result<A>)> k) { |
|
try |
|
{ |
|
throw std::runtime_error(msg); |
|
} |
|
catch (std::exception&) |
|
{ |
|
return k(Result<A>(std::current_exception())); |
|
} |
|
return k(Result<A>(std::exception_ptr())); |
|
}; |
|
} |
|
|
|
namespace detail |
|
{ |
|
template <typename R, typename A, typename B> class BindResultVisitor : public boost::static_visitor<Cont<R,B>> |
|
{ |
|
std::function<Cont<R,B>(A)> m_cont; |
|
|
|
public: |
|
BindResultVisitor(std::function<Cont<R,B>(A)> cont) |
|
: m_cont(cont) |
|
{} |
|
|
|
Cont<R,B> operator()(std::exception_ptr eptr) const |
|
{ |
|
return fail<R,B>(eptr); |
|
} |
|
|
|
Cont<R,B> operator()(A x) const |
|
{ |
|
return m_cont(x); |
|
} |
|
}; |
|
template <typename A> class ExecResultVisitor : public boost::static_visitor<void> |
|
{ |
|
std::function<void(A)> m_success; |
|
std::function<void(std::exception_ptr)> m_failure; |
|
|
|
public: |
|
ExecResultVisitor(std::function<void(A)> success, std::function<void(std::exception_ptr)> failure) |
|
: m_success(success) |
|
, m_failure(failure) |
|
{} |
|
|
|
void operator()(std::exception_ptr eptr) const |
|
{ |
|
return m_failure(eptr); |
|
} |
|
|
|
void operator()(A x) const |
|
{ |
|
return m_success(x); |
|
} |
|
}; |
|
} |
|
|
|
template <typename R, typename A, typename B> |
|
Cont<R,B> bind(Cont<R,A> ktor, std::function<Cont<R,B>(A)> rest) |
|
{ |
|
return [=](std::function<R(Result<B>)> k) { |
|
// std::function<Cont<R,A>(A)> _rest = rest; |
|
std::function<R(Result<A>)> lambda = [k,rest](Result<A> a) { |
|
return boost::apply_visitor(detail::BindResultVisitor<R,A,B>(rest), a)(k); |
|
}; |
|
return ktor(lambda); |
|
}; |
|
}; |
|
|
|
template <typename R, typename A, typename B> |
|
Cont<R,B> fmap(std::function<B(A)> f, Cont<R,A> m) |
|
{ |
|
return bind<R,A,B>(m, [f](A a) { |
|
return pure<R,B>(f(a)); |
|
}); |
|
} |
|
|
|
template <typename A> |
|
void exec(Cont<void,A> m, std::function<void(Result<A>)> f=nullptr) |
|
{ |
|
m(f ? f : [](Result<A>){}); |
|
} |
|
|
|
template <typename A> |
|
void exec(Cont<void,A> m, std::function<void(A)> success, std::function<void(std::exception_ptr)> failure) |
|
{ |
|
std::function<void(Result<A>)> handler = [=](Result<A> result) { |
|
boost::apply_visitor(detail::ExecResultVisitor<A>(success, failure), result); |
|
}; |
|
exec(m, handler); |
|
} |
|
|
|
namespace detail |
|
{ |
|
template <typename A, class C> |
|
Cont<void,A> sequence(std::shared_ptr<C> xs, typename C::iterator it) |
|
{ |
|
return [=](std::function<void(Result<A>)> k) { |
|
if (it != xs->end()) |
|
{ |
|
bind<void,A,A>(*it, [xs,it](A) { |
|
auto it_ = it; |
|
return sequence<A>(xs, ++it_); |
|
})(k); |
|
} |
|
}; |
|
} |
|
} |
|
|
|
template <typename A, class C> |
|
Cont<void,A> sequence(C xs) |
|
{ |
|
auto pxs = std::make_shared<C>(xs); |
|
return detail::sequence<A>(pxs, pxs->begin()); |
|
} |
|
}; |
|
|
|
#endif // HEARHEARME_CONT_HPP_INCLUDED |