-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpattern_matching.cpp
97 lines (84 loc) · 2.39 KB
/
pattern_matching.cpp
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
/*
While the C++ runtime does not have a feature analogous to pattern matching in a
language from the ML family, the C++ constexpr interpreter and template systems can
perform pattern matching computations. Each node type derives from a base class which
can be used to check a how to process each individual node.
This Gist expresses ML like pattern matching: where a standalone function is used
to evaluate the expression. However, with C++ templates and constexpr, the evaluation
function for the expression can be embedded within the type. Where every node type
has a static member function eval that performs its step of the expression. See the
link below for SQL WHERE predicate nodes implementing this pattern:
https://github.com/mkitzan/metaprogramming-optimization/blob/master/include/sql/predicate.hpp
clang -std=c++17 -lstdc++ -o pm pattern_matching.cpp
g++ -std=c++17 -o pm pattern_matching.cpp
For reference this is the SML code implemented in C++17:
datatype expr =
Constant of int
| Negate of expr
| Add of expr * expr
| Multiply of expr * expr
fun eval e =
case e of
Constant(value) => value
| Negate(subexpr) => ~(eval(subexpr))
| Add(left,right) => eval(left) + eval(right)
| Multiply(left,right) => eval(left) * eval(right)
eval(Add(Negate(Constant(10)), Multiply(Constant(2), Constant(26))))
*/
#include <iostream>
struct constant
{};
template <int Value>
struct Constant : constant
{
static constexpr int value{ Value };
};
struct negate
{};
template <typename Subexpr>
struct Negate : negate
{
using subexpr = Subexpr;
};
struct add
{};
template <typename Left, typename Right>
struct Add : add
{
using left = Left;
using right = Right;
};
struct multiply
{};
template <typename Left, typename Right>
struct Multiply : multiply
{
using left = Left;
using right = Right;
};
template <typename Expr>
int constexpr eval()
{
if constexpr (std::is_base_of_v<negate, Expr>)
{
return -eval<typename Expr::subexpr>();
}
else if constexpr (std::is_base_of_v<add, Expr>)
{
return eval<typename Expr::left>() + eval<typename Expr::right>();
}
else if constexpr (std::is_base_of_v<multiply, Expr>)
{
return eval<typename Expr::left>() * eval<typename Expr::right>();
}
else
{
return Expr::value;
}
}
int main()
{
using Expression = Add<Negate<Constant<10>>, Multiply<Constant<2>, Constant<26>>>;
constexpr int result{ eval<Expression>() };
std::cout << result << '\n';
}