Skip to content

Commit 801457f

Browse files
Add name-constrained.c
1 parent 0360089 commit 801457f

File tree

1 file changed

+86
-0
lines changed

1 file changed

+86
-0
lines changed

name-constrained.c

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
#include <stdio.h>
2+
#include <stdlib.h>
3+
#include <string.h>
4+
5+
/* The `Show` typeclass allows types to be turned into their string representation */
6+
typedef struct
7+
{
8+
char* (*const show)(void* self);
9+
} ShowTC;
10+
11+
typedef struct
12+
{
13+
void* self;
14+
ShowTC const* tc;
15+
} Show;
16+
17+
#define CONCAT_(x, y) x ## y
18+
#define CONCAT(x, y) CONCAT_(x, y)
19+
20+
/* Consistently name the impl functions */
21+
#define ImplName(T, TypeclassName) CONCAT(CONCAT(T, _to_), TypeclassName)
22+
23+
/* "Apply" a typeclass over a concrete type */
24+
#define ap(x, T, TypeclassName) ImplName(T, TypeclassName)(x)
25+
26+
#define impl_show(T, show_f) \
27+
Show ImplName(T, Show)(T* x) \
28+
{ \
29+
char* (*const show_)(T* self) = (show_f); \
30+
(void)show_; \
31+
static ShowTC const tc = {.show = (char* (*const)(void*))(show_f) }; \
32+
return (Show){.tc = &tc, .self = x}; \
33+
}
34+
35+
/* Polymorphic printing function */
36+
void print(Show showable)
37+
{
38+
char* s = showable.tc->show(showable.self);
39+
puts(s);
40+
free(s);
41+
}
42+
43+
44+
/* A very holy enum */
45+
typedef enum
46+
{
47+
holy,
48+
hand,
49+
grenade
50+
} Antioch;
51+
52+
static inline char* strdup_(char const* x)
53+
{
54+
char* s = malloc((strlen(x) + 1) * sizeof(*s));
55+
strcpy(s, x);
56+
return s;
57+
}
58+
59+
/* The `show` function implementation for `Antioch*` */
60+
static char* antioch_show(Antioch* x)
61+
{
62+
/*
63+
Note: The `show` function of a `Show` typeclass is expected to return a malloc'ed value
64+
The users of a generic `Show` are expected to `free` the returned pointer from the function `show`.
65+
*/
66+
switch (*x)
67+
{
68+
case holy:
69+
return strdup_("holy");
70+
case hand:
71+
return strdup_("hand");
72+
case grenade:
73+
return strdup_("grenade");
74+
default:
75+
return strdup_("breakfast cereal");
76+
}
77+
}
78+
79+
/* Make function to build a generic `Show` out of a concrete type- `Antioch` */
80+
impl_show(Antioch, antioch_show)
81+
82+
int main(void)
83+
{
84+
print(ap(&(Antioch){ holy }, Antioch, Show));
85+
return 0;
86+
}

0 commit comments

Comments
 (0)