Skip to content

Instantly share code, notes, and snippets.

@hazzard993
Last active December 23, 2024 01:07
Show Gist options
  • Save hazzard993/c75e50cb5fd0343e091afd000e2b5e66 to your computer and use it in GitHub Desktop.
Save hazzard993/c75e50cb5fd0343e091afd000e2b5e66 to your computer and use it in GitHub Desktop.
Inline pasteable functional functions for some functional programming in GameMaker (at least to my understanding of FP).
///
/// Performs right-to-left function composition.
///
/// @param {Function[]} ...functions The pipeline of functions to send values through.
/// @returns The head of this pipeline.
var compose = function() {
var functions = [];
for (var i = 0; i < argument_count; ++i) {
array_push(functions, argument[i]);
}
if array_length(functions) == 0 {
return function(arg) { return arg; };
}
if array_length(functions) == 1 {
return functions[0];
}
return array_reduce(functions, function(previous, current) {
return method({ previous, current }, function() {
var arguments = [];
for (var i = 0; i < argument_count; ++i) {
array_push(arguments, argument[i]);
}
var result;
if is_method(current) {
result = method_call(current, arguments);
} else {
result = script_execute_ext(current, arguments);
}
return previous(result);
});
});
}
///
/// Returns a pipeline make up of functions.
///
/// @param {Function[]} ...functions The pipeline of functions to send values through.
/// @returns The head of this pipeline.
var pipe = function() {
var arguments = [];
for (var i = 0; i < argument_count; ++i) {
array_push(arguments, argument[i]);
}
var functions = array_reverse(arguments);
if array_length(functions) == 0 {
return function(arg) { return arg; };
}
if array_length(functions) == 1 {
return functions[0];
}
return array_reduce(functions, function(previous, current) {
return method({ previous, current }, function() {
var arguments = [];
for (var i = 0; i < argument_count; ++i) {
array_push(arguments, argument[i]);
}
var result;
if is_method(current) {
result = method_call(current, arguments);
} else {
result = script_execute_ext(current, arguments);
}
return previous(result);
});
});
}
///
/// Converts a function into a curried equivalent.
/// Can be a workaround for the lack of closures in GML.
/// See https://ramdajs.com/docs/#curry
///
/// @param {Function} f Provided function.
/// @param {Real} n How many parameters it is expecting.
/// @returns {Any} A curried equivalent of the provided function.
var curry = function(f, n) {
var next = function(f, n, args, next) {
if array_length(args) < n {
return method({ f, n, args, next }, function() {
var new_args = variable_clone(args);
for (var i = 0; i < argument_count; ++i) {
array_push(new_args, argument[i]);
}
return next(f, n, new_args, next);
});
}
if is_method(f) {
return method_call(f, args);
}
return script_execute_ext(f, args);
};
return next(f, n, [], next);
};
///
/// Debugging tool for closures. Returns a string describing the closure.
/// The <> denotes parameters that haven't arrived yet.
///
/// @param {Callable} curry_function The curried function.
/// @returns {String} A string describing the state of the curried function.
var curry_debug = function(curry_function) {
if not is_callable(curry_function) {
return string(curry_function);
}
var ctx = method_get_self(curry_function);
var result = $"{script_get_name(ctx.f)}(";
for (var i = 0; i < ctx.n; ++i) {
if i <= array_length(ctx.args) {
result += chr(97 + i);
} else {
result += $"<{i - array_length(ctx.args)}>";
}
if i >= ctx.n - 1 {
continue;
}
result += ", ";
}
result += ")";
return result;
};
/// @param {Struct} a Struct a
/// @param {Struct} b Struct b
/// @returns A new struct combining both a and b's fields, however b's values take precedent.
var struct_merge = function(a, b) {
var result = variable_clone(a);
var names = struct_get_names(b);
for (var i = 0; i < array_length(names); ++i) {
var name = names[i];
struct_set(result, name, struct_get(b, name));
}
return result;
};
/// @param {String | Real} name The name/field to check.
/// @param {Any} value The value to check that field for (== equality).
/// @returns {Function(Struct) -> Boolean} A function that returns a boolean when given a struct.
var name_equals = function(name, value) {
return method({ name, value }, function(struct) {
return struct_get(struct, name) == value;
});
};
/// @param {Function} constructor_name The constructor to check for.
/// @returns {Function(Struct) -> Boolean} A function that'll check for a struct using is_instanceof.
var is_an_instanceof = function(constructor_name) {
return method({ constructor_name }, function(struct) {
return is_instanceof(struct, constructor_name);
});
};
/// @param {Array} array This array will not be modified.
/// @param {Any[]} ...values Additional values to append.
/// @returns A copy of the array with all additional values appended.
var append = function(array) {
var result = variable_clone(array)
for (var i = 1; i < argument_count; ++i) {
array_push(result, argument[i]);
}
return result;
};
///
/// Flattens an array of arrays.
///
/// [[1, 2], [3, 4]] -> [1, 2, 3, 4]
///
/// @param {Array} array An array of arrays to flatten.
/// @returns A new flatten array based off the given one.
var flatten = function(array) {
var result = [];
for (var i = 0; i < array_length(array); ++i) {
var subarray = array[i];
if not is_array(subarray) {
array_push(result, subarray);
}
for (var j = 0; j < array_length(subarray); ++j) {
var item = subarray[j];
array_push(result, item);
}
}
return result;
};
/// @param {Array} array The array to analyze.
/// @param {Any} value The index to remove.
/// @returns A copy of the array with the specified index removed.
var remove = function(array, index) {
var result = [];
for (var i = 0; i < argument_count; ++i) {
var item = array[i];
if i == index {
continue;
}
array_push(result, value);
}
return result;
};
/// @param {Array} array An array to iterate through.
/// @param {String} seperator A seperator to put in between each stringed item.
/// @returns {String} All items stringified with the use of a seperator in between.
var join = function(array, seperator) {
var result = "";
for (var i = 0; i < array_length(array); ++i) {
var item = array[i];
result += string(item);
if i >= array_length(array) - 1 {
continue;
}
result += seperator;
}
return result;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment