Skip to content

Instantly share code, notes, and snippets.

@bzar
Last active August 29, 2015 14:11
Show Gist options
  • Save bzar/00765d257322cf77309b to your computer and use it in GitHub Desktop.
Save bzar/00765d257322cf77309b to your computer and use it in GitHub Desktop.
Algebraic datatype emulation in C++ (and the same in Rust)
#include <iostream>
#include <cassert>
#include <string>
// Algebraic type
enum ShapeType { CIRCLE, RECTANGLE, ZERO };
struct Circle { int cx, cy, r; static const ShapeType type = CIRCLE; };
struct Rectangle { int x, y, w, h; static const ShapeType type = RECTANGLE; };
struct Zero { static const ShapeType type = ZERO; };
struct Shape {
ShapeType const type;
Shape(Circle const& v) : type(CIRCLE), circle(v) {}
Shape(Rectangle const& v) : type(RECTANGLE), rectangle(v) {}
Shape(Zero const& v) : type(ZERO), zero(v) {}
union {
Circle circle;
Rectangle rectangle;
Zero zero;
};
};
// Generic matching
template<typename R, typename C, typename T, typename F , typename... Args>
R match(C const& c, T C::* tp, F f, Args... args)
{
if(c.type == (c.*tp).type)
{
return f(c.*tp);
}
else
{
return match<R, C>(c, args...);
}
}
template<typename R, typename C, typename F>
R match(C const& c, F f)
{
return f();
}
template<typename R, typename C>
R match(C const& c)
{
assert(false);
}
// Matching print
void print(Shape const& s)
{
match<void>(s,
&Shape::circle, [](Circle const& c) {
std::cout << "Circle { " << c.cx << ", " << c.cy << ", " << c.r << " }" << std::endl;
},
&Shape::rectangle, [](Rectangle const& r) {
std::cout << "Rectangle { " << r.x << ", " << r.y << ", " << r.w << ", " << r.h << " }" << std::endl;
},
&Shape::zero, [](Zero const& z) {
std::cout << "Zero {}" << std::endl;
});
}
int main(int argc, char** argv) {
// Do some shapes
Shape s1 = Circle {1,2,3};
Shape s2 = Rectangle {1,2,3,4};
Shape s3 = Zero {};
// Call lambda on match
auto s2s = match<std::string>(s2,
&Shape::circle, [](Circle const& c) { return "Circle!"; },
&Shape::rectangle, [](Rectangle const& r) { return "Rectangle!"; },
[]() { return "Other"; });
std::cout << s2s << std::endl;
// Print all
print(s1);
print(s2);
print(s3);
}
enum Shape {
Circle(int, int, int),
Rectangle(int, int, int, int),
Zero
}
fn print(s: Shape) {
match s {
Circle(cx, cy, r) => println!("Circle {{ {}, {}, {} }}", cx, cy, r),
Rectangle(x, y, w, h) => println!("Rectangle {{ {}, {}, {}, {} }}", x, y, w, h),
Zero => println!("Zero")
}
}
fn main() {
let s1 = Circle(1,2,3);
let s2 = Rectangle(1,2,3,4);
let s3 = Zero;
let s2s = match s2 {
Circle(_, _, _) => "Circle!",
Rectangle(_, _, _, _) => "Rectangle!",
_ => "Other"
};
println!("{}", s2s);
print(s1);
print(s2);
print(s3);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment