Skip to content

Instantly share code, notes, and snippets.

@lukechampine
Last active November 14, 2023 18:22
Show Gist options
  • Star 21 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save lukechampine/c460fb2754ef0a7f7652874d9f9ed678 to your computer and use it in GitHub Desktop.
Save lukechampine/c460fb2754ef0a7f7652874d9f9ed678 to your computer and use it in GitHub Desktop.
Maybe and Either Monads in C
#include <stdio.h>
#include <stdbool.h>
// Maybe
typedef struct MaybeInt {
int just;
bool nothing;
} MaybeInt;
const MaybeInt Nothing = (MaybeInt) { .nothing = true };
MaybeInt returnMaybe(int x) { return (MaybeInt) { .just = x, .nothing = false }; }
MaybeInt bindMaybe(MaybeInt (*fn)(int), MaybeInt m) {
return m.nothing ? Nothing : fn(m.just);
}
void printMaybe(MaybeInt m) {
if (m.nothing) printf("Nothing\n");
else printf("%d\n", m.just);
}
MaybeInt maybeFoo(int x) { return (x < 1) ? Nothing : returnMaybe(x - 3); }
MaybeInt maybeBar(int x) { return (x > 0) ? Nothing : returnMaybe(x + 3); }
MaybeInt maybeBaz(int x) { return (x != 2) ? Nothing : returnMaybe(x); }
// Either
typedef struct EitherInt {
int i;
char* error;
} EitherInt;
EitherInt returnInt(int i) { return (EitherInt) { .i = i, .error = NULL }; }
EitherInt returnError(char* e) { return (EitherInt) { .i = 0, .error = e }; }
EitherInt bindEither(EitherInt (*fn)(int), EitherInt m) {
return (m.error != NULL) ? m : fn(m.i);
}
void printEither(EitherInt m) {
if (m.error != NULL) printf("%s\n", m.error);
else printf("%d\n", m.i);
}
EitherInt eitherFoo(int x) { return (x < 2) ? returnError("too small") : returnInt(x - 3); }
EitherInt eitherBar(int x) { return (x > 0) ? returnError("not negative") : returnInt(x + 3); }
EitherInt eitherBaz(int x) { return (x != 2) ? returnError("must be 2") : returnInt(x); }
int main() {
MaybeInt m = bindMaybe(maybeBaz, bindMaybe(maybeBar, maybeFoo(7)));
printMaybe(m); // "Nothing"
m = bindMaybe(maybeBaz, bindMaybe(maybeBar, maybeFoo(2)));
printMaybe(m); // "2"
EitherInt e = bindEither(eitherBaz, bindEither(eitherBar, eitherFoo(7)));
printEither(e); // "not negative"
e = bindEither(eitherBaz, bindEither(eitherBar, eitherFoo(2)));
printEither(e); // "2"
return 0;
}
@egoarka
Copy link

egoarka commented Dec 10, 2018

Was searching for implementation in google and stumbled here.
Looks cool 👍 !

How do you think: is it applicable in real-world c program?
I think yes, but it needs to have many others data structures implementations to write c code more easily.

Copy link

ghost commented Apr 12, 2023

you could also use a union:

typedef struct EitherInt {
    union {
        int   i;
        char* error;
    };
    bool is_error;
} EitherInt;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment