Last active
August 29, 2015 14:22
-
-
Save codebje/ad3059ea01214d2f6b7c to your computer and use it in GitHub Desktop.
A badly written monad in C
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <assert.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#define OPTIONAL_INIT(t) typedef struct optional_ ## t { short isPresent; t value; } optional_ ## t | |
#define OPTIONAL(t) optional_ ## t | |
static short _optional_empty = 0; | |
struct optional_any { short isPresent; int value; }; | |
static inline struct optional_any *_unit(size_t os, size_t vs, const char *v) { | |
struct optional_any *o = malloc(os); | |
o->isPresent = 1; | |
memcpy(&(o->value), v, vs); | |
return o; | |
} | |
#define OPTIONAL_UNIT(t, v) ((OPTIONAL(t) *)_unit(sizeof(OPTIONAL(t)), sizeof(t), (const char *)&v)) | |
#define OPTIONAL_EMPTY(t) ((OPTIONAL(t) *)&_optional_empty) | |
#define OPTIONAL_BIND(t, o, f) (o->isPresent ? f(o->value) : OPTIONAL_EMPTY(t)) | |
/* Declare an optional int type */ | |
OPTIONAL_INIT(int); | |
OPTIONAL(int) *maybe_double(int arg) { | |
int val = arg * 2; | |
return OPTIONAL_UNIT(int, val); | |
} | |
OPTIONAL(int) *maybe_plus_two(int arg) { | |
int val = arg + 2; | |
return OPTIONAL_UNIT(int, val); | |
} | |
typedef OPTIONAL(int) * (*fn)(int); | |
/* composition in C: messy. */ | |
static fn f = maybe_double; | |
static fn g = maybe_plus_two; | |
OPTIONAL(int) *f_bind_g(int v) { | |
return OPTIONAL_BIND(int, f(v), g); | |
} | |
/* Helper for right identitiy law */ | |
OPTIONAL(int) *unit(int v) { | |
return OPTIONAL_UNIT(int, v); | |
} | |
int main(int argc, char **argv) { | |
int myval = 5; | |
OPTIONAL(int) *optint = OPTIONAL_UNIT(int, myval); | |
// left identity: bind(unit(v), f) === f(v) | |
OPTIONAL(int) *left1 = OPTIONAL_BIND(int, optint, maybe_double); | |
OPTIONAL(int) *left2 = maybe_double(myval); | |
assert(left1->value == left2->value); | |
// right identity: bind(m, unit) === m | |
OPTIONAL(int) *right = OPTIONAL_BIND(int, optint, unit); | |
assert(right->value == optint->value); | |
// associativity | |
OPTIONAL(int) *assoc1 = OPTIONAL_BIND(int, OPTIONAL_BIND(int, optint, maybe_double), maybe_plus_two); | |
OPTIONAL(int) *assoc2 = OPTIONAL_BIND(int, optint, f_bind_g); | |
assert(assoc1->value == assoc2->value); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment