Skip to content

Commit ef1cc0f

Browse files
author
ikrima
committed
[plt] notes on final tagless for shallow embedding dsl's
1 parent cbcb0c4 commit ef1cc0f

File tree

2 files changed

+531
-0
lines changed

2 files changed

+531
-0
lines changed
Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
2+
````cpp
3+
// From https://i.cs.hku.hk/~bruno/oa/
4+
#include <iostream>
5+
#include <string>
6+
#include <memory>
7+
using namespace std;
8+
9+
/*
10+
* This program has used some C++11 features to get rid of manual memory management.
11+
*
12+
* If you prefer the older C++ version, do the follwing steps:
13+
* 1. Switch all "EvalPtr" to "Eval *"; do the same to "PPrintPtr"
14+
* WARNING: you need to do some additional cleanup for those newed objects
15+
* 2. Replace "make_shared<Closure>" with "new Closure"
16+
* 3. Substitude "to_string" to some other ways of converting int to string
17+
*/
18+
19+
// Initial object algebra interface for expressions: integers and addition
20+
template <typename E>
21+
class ExpAlg
22+
{
23+
public:
24+
virtual E lit(int x) = 0;
25+
virtual E add(E e1, E e2) = 0;
26+
};
27+
28+
// An object algebra implementing that interface (evaluation)
29+
30+
// The evaluation interface
31+
class Eval
32+
{
33+
public:
34+
virtual int eval() = 0;
35+
};
36+
typedef shared_ptr<Eval> EvalPtr;
37+
38+
class EvalLit : public Eval {
39+
public:
40+
EvalLit(int x) : _x(x) {}
41+
42+
virtual int eval() {
43+
return _x;
44+
}
45+
private:
46+
int _x;
47+
};
48+
49+
class EvalAdd : public Eval {
50+
public:
51+
EvalAdd(EvalPtr l, EvalPtr r) : _l(l), _r(r) {}
52+
53+
virtual int eval() {
54+
return _l->eval() + _r->eval();
55+
}
56+
private:
57+
EvalPtr _l;
58+
EvalPtr _r;
59+
};
60+
61+
// The object algebra
62+
class EvalExpAlg : virtual public ExpAlg<EvalPtr>
63+
{
64+
public:
65+
virtual EvalPtr lit(int x) {
66+
return make_shared<EvalLit>(x);
67+
}
68+
69+
virtual EvalPtr add(EvalPtr e1, EvalPtr e2) {
70+
return make_shared<EvalAdd>(e1, e2);
71+
}
72+
};
73+
74+
// Evolution 1: Adding subtraction
75+
template<typename E>
76+
class SubExpAlg : virtual public ExpAlg<E>
77+
{
78+
public:
79+
virtual E sub(E e1, E e2) = 0;
80+
};
81+
82+
class EvalSub : public Eval {
83+
public:
84+
EvalSub(EvalPtr l, EvalPtr r)
85+
: _l(l), _r(r) {}
86+
87+
int eval() {
88+
return _l->eval() - _r->eval();
89+
}
90+
private:
91+
EvalPtr _l;
92+
EvalPtr _r;
93+
};
94+
95+
// Updating evaluation:
96+
class EvalSubExpAlg : public EvalExpAlg, public SubExpAlg<EvalPtr>
97+
{
98+
public:
99+
virtual EvalPtr sub(EvalPtr e1, EvalPtr e2) {
100+
return make_shared<EvalSub>(e1, e2);
101+
}
102+
};
103+
104+
105+
// Evolution 2: Adding pretty printing
106+
class PPrint
107+
{
108+
public:
109+
virtual string print() = 0;
110+
};
111+
112+
typedef shared_ptr<PPrint> PPrintPtr;
113+
114+
class PrintLit : public PPrint
115+
{
116+
public:
117+
PrintLit(int x) : _x(x) {}
118+
119+
virtual string print() {
120+
return to_string(_x);
121+
}
122+
private:
123+
int _x;
124+
};
125+
126+
class PrintAdd : public PPrint
127+
{
128+
public:
129+
PrintAdd(PPrintPtr e1, PPrintPtr e2)
130+
: _e1(e1), _e2(e2) {}
131+
132+
virtual string print() {
133+
return _e1->print() + " + " + _e2->print();
134+
}
135+
136+
private:
137+
PPrintPtr _e1;
138+
PPrintPtr _e2;
139+
};
140+
141+
class PrintSub : public PPrint
142+
{
143+
public:
144+
PrintSub(PPrintPtr e1, PPrintPtr e2)
145+
: _e1(e1), _e2(e2) {}
146+
virtual string print() {
147+
return _e1->print() + " - " + _e2->print();
148+
}
149+
private:
150+
PPrintPtr _e1;
151+
PPrintPtr _e2;
152+
};
153+
154+
class PrintExpAlg : virtual public SubExpAlg<PPrintPtr>
155+
{
156+
public:
157+
virtual PPrintPtr lit(int x) {
158+
return make_shared<PrintLit>(x);
159+
}
160+
161+
virtual PPrintPtr add(PPrintPtr e1, PPrintPtr e2) {
162+
return make_shared<PrintAdd>(e1, e2);
163+
}
164+
165+
virtual PPrintPtr sub(PPrintPtr e1, PPrintPtr e2) {
166+
return make_shared<PrintSub>(e1, e2);
167+
}
168+
};
169+
170+
// An alternative object algebra for pretty printing
171+
class PrintExpAlg2 : virtual public SubExpAlg<string>
172+
{
173+
public:
174+
virtual string lit(int x) {
175+
return to_string(x);
176+
}
177+
178+
virtual string add(string e1, string e2) {
179+
return e1 + " + " + e2;
180+
}
181+
182+
virtual string sub(string e1, string e2) {
183+
return e1 + " - " + e2;
184+
}
185+
};
186+
187+
// Testing
188+
189+
190+
// An expression using the basic ExpAlg
191+
template<typename E>
192+
E exp1(ExpAlg<E>& alg) {
193+
return alg.add(alg.lit(3), alg.lit(4));
194+
}
195+
196+
// An expression using subtraction too
197+
template<typename E>
198+
E exp2(SubExpAlg<E>& alg) {
199+
return alg.sub(exp1(alg), alg.lit(4));
200+
}
201+
202+
int main() {
203+
// Some object algebras:
204+
EvalExpAlg ea;
205+
EvalSubExpAlg esa;
206+
PrintExpAlg pa;
207+
PrintExpAlg2 pa2;
208+
209+
EvalPtr ev = exp1(esa);
210+
211+
// But calling ea with exp2 is an error
212+
// EvalPtr ev_bad = exp2(ea);
213+
214+
cout << "Evaluation of exp1 \"" << exp1(pa)->print() << "\" is: " << ev->eval() << endl;
215+
cout << "Evaluation of exp2 \"" << exp2(pa)->print() << "\" is: " << exp2(esa)->eval() << endl;
216+
cout << "The alternative pretty printer works nicely too!\n"
217+
<< "exp1: " << exp1(pa2) << "\n"
218+
<< "exp2: " << exp2(pa2);
219+
}
220+
````

0 commit comments

Comments
 (0)