Skip to content

Instantly share code, notes, and snippets.

@Biotronic
Created October 30, 2014 14:53
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Biotronic/253ee5eee8623f9471dd to your computer and use it in GitHub Desktop.
Save Biotronic/253ee5eee8623f9471dd to your computer and use it in GitHub Desktop.
import std.typecons;
import std.traits;
import std.typetuple;
import std.stdio : writeln;
struct Maybe(T) {
T value = void;
bool b = true;
@property static Maybe None() {
Maybe result;
result.b = false;
return result;
}
}
bool isNone(T)(T a) if (isMaybe!T) {
return !a.b;
}
bool isNone(T)(T a) if (!isMaybe!T) {
return false;
}
enum isMaybe(T) = is(T == Maybe!U, U);
unittest {
assert(isMaybe!(Maybe!int));
assert(!isMaybe!string);
}
template staticMap(alias Fn) {
alias staticMap = TypeTuple!();
}
template staticMap(alias Fn, T...) {
alias staticMap = TypeTuple!(Fn!(T[0]), staticMap!(Fn, T[1..$]));
} unittest {
assert([staticMap!(isMaybe, int, string, Maybe!float)] == [false, false, true]);
}
template canCall(alias Fn, Args...) {
enum canCall = __traits(compiles, (Args args)=>Fn(args));
} unittest {
assert(canCall!(main));
assert(canCall!((int a, float b)=>a+b, int, float));
assert(canCall!((int a, float b)=>a+b, int, int));
}
template RemoveMaybe(T) {
static if (is(T == Maybe!U, U)) {
alias RemoveMaybe = U;
} else {
alias RemoveMaybe = T;
}
} unittest {
assert(is(RemoveMaybe!int == int));
assert(is(RemoveMaybe!(Maybe!int) == int));
}
template goodArgs(alias Fn, Args...) {
enum goodArgs = canCall!(Fn, staticMap!(RemoveMaybe, Args));
}
auto unsafeFetchFromMaybe(T)(T value) if (isMaybe!T) {
return value.value;
}
T unsafeFetchFromMaybe(T)(T value) if (!isMaybe!T) {
return value;
}
template tupleMap(alias Fn) {
auto tupleMap(Args...)(Args args) {
static if (Args.length > 1) {
return tuple(Fn(args[0]), tupleMap(args[1..$]).expand);
} else {
return tuple(Fn(args[0]));
}
}
} unittest {
assert(tupleMap!(a=>a+1)(1, 2.4, 3.5f) == tuple(2, 3.4, 4.5f));
}
bool anyNone(Args...)(Args args) {
static if (Args.length == 0) {
return false;
} else if (isNone(args[0])) {
return true;
} else {
return anyNone(args[1..$]);
}
} unittest {
assert(!anyNone());
assert(!anyNone(3));
assert(!anyNone("None"));
assert(anyNone(Maybe!int.None));
}
template maybe(alias Fn) {
auto maybe(Args...)(Args args) if (goodArgs!(Fn, Args)) {
alias TResult = ReturnType!(typeof((staticMap!(RemoveMaybe, Args) cleanedArgs) {return Fn(cleanedArgs);}));
if (anyNone(args)) {
return Maybe!TResult.None;
} else {
auto fixedArgs = tupleMap!(unsafeFetchFromMaybe)(args).expand;
return Maybe!(TResult)(Fn(fixedArgs));
}
}
}
int add(int a, int b) {
return a + b;
}
void main() {
auto a = maybe!add(Maybe!int.None, 3);
assert(isNone(a));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment