language: C++11 (gcc-4.7.2)
date: 166 days 5 hours ago
link:
visibility: private
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#include <utility>
#include <type_traits>
 
// SFINAE utility
template<typename...> struct void_ { using type = void; };
template<typename... T> using Void = typename void_<T...>::type;
 
/*
 * In an ideal world std::result_of would just work instead of all that.
 * Consider this as a write-once (until std::result_of is fixed), use-many
 * situation.
 */    
template<typename Sig, typename Sfinae = void> struct result_of {};
template<typename F, typename... Args>
struct result_of<
    F(Args...)
    , Void<decltype(std::declval<F>()(std::declval<Args>()...))>
> {
    using type = decltype(std::declval<F>()(std::declval<Args>()...));
};
template<typename Sig> using ResultOf = typename result_of<Sig>::type;
 
/*
 * Note how both template parameters have kind *, MonadicValue would be
 * m a, not m. We don't whether MonadicValue is a specialization of some M<T>
 * or not (or derived from a specialization of some M<T>). Note that it is
 * possible to retrieve the a in M a via typename MonadicValue::value_type
 * if MonadicValue is indeed a model of the proper concept.
 *
 * Defer actual implementation to the operator() of MonadicValue,
 * which will do the monad-specific operation
 */
template<
    typename MonadicValue
    , typename F
    /* It is possible to put a self-documenting assertion here
       that will *not* SFINAE out but truly result in a hard error
       unless some conditions are not satisfied -- I leave this out
       for brevity
    , Requires<
        MonadicValueConcept<MonadicValue>
        // The two following constraints ensure that
        // F has signature a -> m b
        , Callable<F, ValueType<MonadicValue>>
        , MonadicValueConcept<ResultOf<F(ValueType<MonadicValue>)>>
    >...
    */
>
ResultOf<MonadicValue(F)>
bind(MonadicValue&& value, F&& f)
{ return std::forward<MonadicValue>(value)(std::forward<F>(f)); }
 
// Picking Maybe as an example monad because it's easy
template<typename T>
struct just_type {
    using value_type = T;
 
    // Encapsulation omitted for brevity
    value_type value;
 
    template<typename F>
    // The use of ResultOf means that we have a soft contraint
    // here, but the commented Requires clause in bind happens
    // before we would end up here
    ResultOf<F(value_type)>
    operator()(F&& f)
    { return std::forward<F>(f)(value); }
};
 
template<typename T>
just_type<T> just(T&& t)
{ return { std::forward<T>(t) }; }
 
template<typename T>
just_type<typename std::decay<T>::type> make_just(T&& t)
{ return { std::forward<T>(t) }; }
 
struct nothing_type {
    // Note that because nothing_type and just_type<T>
    // are part of the same concept we *must* put in
    // a value_type member type -- whether you need
    // a value member or not however is a design
    // consideration with trade-offs
    struct universal { template<typename T> operator T(); };
    using value_type = universal;
 
    template<typename F>
    nothing_type operator()(F const&) const
    { return {}; }
};
constexpr nothing_type nothing;
    
#include <cassert>
    
int main()
{
    auto maybe = make_just(4);
    auto f = [](int i) { return just("Hello, World!"[i]); };
    auto&& r0 = bind(maybe, f);
    auto&& r1 = bind(bind(make_just(6), [](int i) { return just(i - 2); }), f);
    assert( &r0.value == &r1.value );
    auto r2 = bind(nothing, f);
    auto r3 = bind(maybe, [](int) { return nothing; });
    static_assert( std::is_same<decltype(r2), nothing_type>::value, "" );
    static_assert( std::is_same<decltype(r3), nothing_type>::value, "" );
}
prog.cpp:5:44: error: expected nested-name-specifier before 'type'
prog.cpp:5:44: error: using-declaration for non-member at class scope
prog.cpp:5:49: error: expected ';' before '=' token
prog.cpp:5:49: error: expected unqualified-id before '=' token
prog.cpp:6:25: error: expected unqualified-id before 'using'
prog.cpp:17:7: error: 'Void' was not declared in this scope
prog.cpp:17:64: error: template argument 2 is invalid
prog.cpp:18:1: error: expected unqualified-id before '>' token
prog.cpp:21:24: error: expected unqualified-id before 'using'
prog.cpp:49:1: error: 'ResultOf' does not name a type
prog.cpp:54:1: error: expected unqualified-id before 'template'
prog.cpp:71:1: error: 'just_type' does not name a type
prog.cpp:74:1: error: expected unqualified-id before 'template'
prog.cpp:85:11: error: expected nested-name-specifier before 'value_type'
prog.cpp:85:11: error: using-declaration for non-member at class scope
prog.cpp:85:22: error: expected ';' before '=' token
prog.cpp:85:22: error: expected unqualified-id before '=' token
prog.cpp:91:24: error: missing initializer for constexpr 'nothing'
prog.cpp: In function 'int main()':
prog.cpp:97:29: error: 'make_just' was not declared in this scope
prog.cpp:97:29: error: unable to deduce 'auto' from '<expression error>'
prog.cpp: In lambda function:
prog.cpp:98:56: error: 'just' was not declared in this scope
prog.cpp:98:59: error: return-statement with a value, in function returning 'void'
prog.cpp: In function 'int main()':
prog.cpp:99:30: error: 'bind' was not declared in this scope
prog.cpp:99:30: error: unable to deduce 'auto&&' from '<expression error>'
prog.cpp: In lambda function:
prog.cpp:100:70: error: 'just' was not declared in this scope
prog.cpp:100:73: error: return-statement with a value, in function returning 'void'
prog.cpp: In function 'int main()':
prog.cpp:100:78: error: unable to deduce 'auto&&' from '<expression error>'
prog.cpp:102:30: error: unable to deduce 'auto' from '<expression error>'
prog.cpp:103:54: error: unable to deduce 'auto' from '<expression error>'
prog.cpp:104:59: error: template argument 1 is invalid
prog.cpp:105:59: error: template argument 1 is invalid