@@ -16,7 +16,6 @@
1616#define purescript_H
1717
1818#include <memory>
19−#include <functional>
2019#include <deque>
2120#include <string>
2221#include <limits>
@@ -29,6 +28,7 @@ namespace purescript {
2928
3029 class boxed {
3130 std::shared_ptr<void> shared;
31+
3232 public:
3333 union {
3434 int _int_;
@@ -36,8 +36,38 @@ namespace purescript {
3636 bool _bool_;
3737 };
3838
39− using fn_t = std::function<boxed(const boxed&)>;
40− using eff_fn_t = std::function<boxed(void)>;
39+ class fn_t {
40+ public:
41+ virtual ~fn_t() {}
42+ virtual auto operator ()(const boxed&) const -> boxed = 0;
43+ };
44+
45+ template <typename T>
46+ class fn_template_t : public fn_t {
47+ T fn;
48+ public:
49+ fn_template_t(T f) : fn(std::move(f)) {}
50+ auto operator ()(const boxed& arg) const -> boxed override {
51+ return fn(arg);
52+ }
53+ };
54+
55+ class eff_fn_t {
56+ public:
57+ virtual ~eff_fn_t() {}
58+ virtual auto operator ()() const -> boxed = 0;
59+ };
60+
61+ template <typename T>
62+ class eff_fn_template_t : public eff_fn_t {
63+ T fn;
64+ public:
65+ eff_fn_template_t(T f) : fn(std::move(f)) {}
66+ auto operator ()() const -> boxed override {
67+ return fn();
68+ }
69+ };
70+
4171 using dict_t = string_literal_dict_t<boxed>;
4272 using array_t = std::deque<boxed>;
4373
@@ -81,16 +111,18 @@ namespace purescript {
81111
82112 template <typename T,
83113 typename = typename std::enable_if<!std::is_same<boxed,T>::value>::type>
84− boxed(const T& f,
85− typename std::enable_if<std::is_assignable<std::function<boxed(boxed)>,T>::value>::type* = 0)
86− : shared(std::make_shared<fn_t>(f)) {
114+ boxed(T f,
115+ typename std::enable_if<std::is_same<decltype(std::declval<T>()(std::declval<boxed>())),
116+ boxed>::value>::type* = 0)
117+ : shared(std::make_shared<fn_template_t<T>>(std::move(f))) {
87118 }
88119
89120 template <typename T,
90121 typename = typename std::enable_if<!std::is_same<boxed,T>::value>::type>
91− boxed(const T& f,
92− typename std::enable_if<std::is_assignable<std::function<boxed(void)>,T>::value>::type* = 0)
93− : shared(std::make_shared<eff_fn_t>(f)) {
122+ boxed(T f,
123+ typename std::enable_if<std::is_same<decltype(std::declval<T>()()),
124+ boxed>::value>::type* = 0)
125+ : shared(std::make_shared<eff_fn_template_t<T>>(std::move(f))) {
94126 }
95127
96128 inline auto get() const noexcept -> void * {