Functional Programming Utilities for WurstScript inspired by Lodash
This library provides utility functions for operating on LinkedList and IterableMap objects as well as utility classes Range and Pair. These functions will attempt to destroy the lists and maps that they act upon unless they are explicitly owned.
function ownList<T>(LinkedList<T> list) returns OwnedLinkedList<T>Own a list preventing automatic deletion by Lodash methods. Example:
let list = asList(1, 2, 3) let myOwnedList = ownList(list)function ownMap<K, V>(IterableMap<K, V> map) returns OwnedIterableMap<K, V>Own a map preventing automatic deletion by Lodash methods. Example:
let map = asList(pair(1, 2), pair(2, 3)).fromPairs() let myOwnedMap = ownMap(map)static function Callable.owned(Callable func) returns CallableCreate an owned callable. Example:
let myOwnedFunc = Function<int, string>.owned(x -> x.toString())function range(int min, int max, int incr) returns Range function range(int min, int max) returns Range function range(int max) returns Range function range() returns RangeCreates a range which is iterable from start to finish by incr. Example:
let x = new LinkedList<int> for i from range(0, 10) x.add(i) x // => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] let y = new LinkedList<int> for i from range(4, 10, 2) x.add(i) x // => [4, 6, 8]function rangeStep(int max, int incr) returns RangeCreates a range which is iterable from 0 to finish by incr. Example:
let y = new LinkedList<int> for i from rangeStep(10, 2) x.add(i) x // => [0, 2, 4, 6, 8]function pair<A, B>(A a, B b) returns Pair<A, B>Creates a tuple. Example:
let myBinding = pair(1, "foo")function makeMap<K, V>(vararg Pair<K, V> elems) returns IterableMap<K, V>Make a map from a list of pairs. Example:
makeMap( pair(1, "a"), pair(2, "b"), pair(3, "c"), ) // => { // 1 => "a", // 2 => "b", // 3 => "c" // }abstract class OwnableRepresents an ownable object exposing two methods: own, to claim ownership of an object, and maybeFree, which will destroy the object if unowned.
function Ownable.own()Own's this callable to prevent it from being freed automatically. You must manually destroy this object to free it. Example:
let myPair = pair(1, "a")..own() // this line would free `myPair` unless it was owned let myMap = makeMap(myPair) // do more stuff with `myPair destroy myPair // Callables can also be owned Predicate<int> isEven = x -> x mod 2 == 0 isEven.own()function Ownable.maybeFree() returns boolDestroys this callable if it has not been owned. Returns true if the object was destroyed, otherwise false. Example:
let myOwnedPair = pair(1, "a")..own() let myUnownedPair = pair(2, "b") myOwnedPair.maybeFree() // => false myUnownedPair.maybeFree() // => trueclass Range extends Ownable construct(int start, int finish, int incr)Represents a range of numbers. Can be iterated. Default start is 0, default finish is INT_MAX, default increment amount is 1. Increment can be negative for a backwards range. Example:
let range = new Range(0, 10, 1)function Range.reset()Reset this iterator. Example:
let myRange = range(10) range.next() // => 0 range.reset() range.next() // => 0function Range.toList() returns LinkedList<int>Converts a range to a list. Example:
range(10).toList() // => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]class Pair<A, B> extends Ownable A a B b construct(A a, B b)A tuple which can be cast to index for use in data types. Example:
let pair = new Pair(1, "a")function Pair<A, B>.head() returns AGet the first element of the pair. Example:
let myPair = pair(1, "a") myPair.head() // => 1function Pair<A, B>.tail() returns BGet the last element of the pair. Example:
let myPair = pair(1, "a") myPair.tail() // => "a"This package provides various extension methods for LinkedList and IterableMap. Similar to the WurstFP API, these methods will attempt to destroy the closures and objects they are invoked upon and passed.
function LinkedList<T>.equals<T>(LinkedList<T> b) returns bool function IterableMap<K, V>.equals<K, V>(IterableMap<K, V> b) returns boolChecks for equality of two lists/maps. Example:
let a = asList(1, 2, 3) let b = asOwnedList(1, 2, 3) a.equals(b) // => truefunction LinkedList<T>.takeWhile<T>(BiFunction<T, int, bool> predicate) returns LinkedList<T>Creates a slice of list with elements taken from the beginning. Elements are taken until predicate returns falsey. The predicate is invoked with one to three argument(s): (value, index, list). Example:
asList(0, 1, 2, 3, 4, 5).takeWhile((x, _i) -> x < 3) // => [0, 1, 2]function LinkedList<T>.take<T>(int numElems) returns LinkedList<T>Creates a slice of list with numElems elements taken from the beginning. Example:
asList(1, 2, 3, 4, 5).take(4) // => [1, 2, 3, 4]function LinkedList<T>.foldl<Q, T>(Q startValue, BiFunction<T, Q, Q> transform) returns QReduces collection to a value which is the accumulated result of running each element in collection thru iteratee, where each successive invocation is supplied the return value of the previous. The order if iteration is from left to right. The transform is invoked with two arguments: (accumulator, value). Example:
asList("h", "e", "l", "l", "o").foldl("", (acc, val) -> acc + val) // => "hello"function LinkedList<T>.foldr<Q, T>(Q startValue, BiFunction<T, Q, Q> transform) returns QReduces collection to a value which is the accumulated result of running each element in collection thru iteratee, where each successive invocation is supplied the return value of the previous. The order if iteration is from right to left. The transform is invoked with two arguments: (accumulator, value). Example:
asList("h", "e", "l", "l", "o").foldr("", (acc, val) -> acc + val) // => "olleh"function LinkedList<T>.reduce<T>(BiFunction<T, T, T> transform) returns TReduces collection similar to foldl, except that the initial value is the first element of the collection. Outputs a default value in the case of an empty collection.
asList(1, 2, 3, 4, 5).reduce((value, elem) -> value + elem) // => 15 new LinkedList<int>()).reduce((value, elem) -> value + elem) // => 0 asList("1", "2", "3").reduce((value, elem) -> value + elem) // => "123" new LinkedList<string>().reduce((value, elem) -> value + elem) // => "" asList(asList(1, 2), asList(3, 4)).reduce((value, elem) -> value..addAll(elem)) // => [1, 2, 3, 4] new LinkedList<LinkedList<int>>().reduce((value, elem) -> value..addAll(elem)) // => nullfunction LinkedList<T>.reduce<T>(BiFunction<T, T, T> transform) returns TReduces collection similar to foldr, except that the initial value is the first element of the collection. Outputs a default value in the case of an empty collection.
asList(1, 2, 3, 4, 5).reduce((value, elem) -> value + elem) // => 15 new LinkedList<int>()).reduce((value, elem) -> value + elem) // => 0 asList("1", "2", "3").reduce((value, elem) -> value + elem) // => "321"function LinkedList<T>.every<T>(Predicate<T> predicate) returns boolChecks if predicate returns truthy for all elements of collection. Iteration is stopped once predicate returns falsey. The predicate is invoked with one argument: (value). Example:
asList(1, 2, 3, 4, 5).every(x -> x < 9) // => true asList(1, 2, 3, 4, 5).every(x -> x < 5) // => falsefunction LinkedList<T>.any<T>(Predicate<T> predicate) returns boolChecks if predicate returns truthy for any element of collection. Iteration is stopped once predicate returns truthy. The predicate is invoked with one argument: (value). Example:
asList(1, 2, 3, 4, 5).any(x -> x < 2) // => true asList(1, 2, 3, 4, 5).any(x -> x > 9) // => falsefunction LinkedList<string>.join(string separator) returns stringConcatenates the strings in a list using a given separator. Example:
asList("a", "b", "c").join(", ") // => "a, b, c"function IterableMap<T, Q>.keys<T, Q>() returns LinkedList<T>Creates a list of the keys of map. Example:
let map = makeMap( pair("a", "apple"), pair("p", "pear"), pair("o", "orange") ).keys() // => ["a", "p", "o"]function IterableMap<T, Q>.values<T, Q>() returns LinkedList<Q>Creates a list of the values of map. Example:
let map = makeMap( pair("a", "apple"), pair("p", "pear"), pair("o", "orange") ).keys() // => ["apple", "pear", "orange"]function LinkedList<T>.map<T, Q>(BiFunction<T, int, Q> transform) returns LinkedList<Q> function IterableMap<S, T>.map<S, T, R>(BiFunction<S, T, R> transform) returns LinkedList<R>Creates a list of values by running each element in collection thru transform. The transform for lists is invoked with one or two argument(s): (value, index). The transform for maps is invoked with two arguments: (key, value). Example:
asList(1, 2, 3).map(x -> x.squared()) // => [1, 4, 9]function LinkedList<LinkedList<T>>.flatten<T>() returns LinkedList<T>Flattens list a level less deep. Example:
asList( asList(1, 2, 3), asList(4, 5), asList(6) ).flatten() // => [1, 2, 3, 4, 5, 6]function LinkedList<T>.drop<T>(int numElems) returns LinkedList<T>Creates a slice of list with numELems elements dropped from the beginning. Example:
asList(1, 2, 3, 4, 5, 6).drop(2) // => [3, 4, 5, 6]function LinkedList<T>.lodashFilter<T>(Predicate<T> filter) returns LinkedList<T>Iterates over elements of list, returning a list of all elements predicate returns truthy for. The predicate is invoked with one argument: (value).
asList(1, 2, 3, 4, 5).lodashFilter(x -> x mod 2 == 0) // => [2, 4]function LinkedList<int>.sum() returns int function LinkedList<real>.sum() returns realComputes the sum of the values in list. Example:
asList(1, 2, 3).sum() // => 6 asList(1.1, 2.2, 3.3).sum() // => 6.6function LinkedList<int>.max() returns int function LinkedList<real>.max() returns realComputes the max of the values in list. Example:
asList(1, 2, 3).max() // => 3 asList(1.1, 2.2, 3.3).max() // => 3.3function LinkedList<int>.min() returns int function LinkedList<real>.min() returns realComputes the min of the values in list. Example:
asList(1, 2, 3).min() // => 1 asList(1.1, 2.2, 3.3).min() // => 1.1function LinkedList<int>.mean() returns real function LinkedList<real>.mean() returns realComputes the arithmetic mean of the values in list. Example:
asList(1, 2, 3).mean() // => 2 asList(1, 2, 3, 4).mean() // => 2.5 asList(1.1, 2.2, 3.3).min() // => 2.2function LinkedList<T>.length<T>() returns intGets the length of list and maybe frees it. Example:
asList(1, 2, 3).length() // => 3function LinkedList<T>.each<T>(VoidFunction<T> func) function LinkedList<T>.each<T>(VoidBiFunction<T, int> func)Iterates over elements of collection and invokes iteratee for each element. The iteratee is invoked with one or two argument(s): (value, index). Example:
asList(1, 2, 3).each(x -> print(x))function LinkedList<A>.zipObject<A, B>(LinkedList<B> lst) returns IterableMap<A, B>Creates an IterableMap with the keys from A and the values from B. Example:
asList(1, 2, 3).zipObject(asList("a", "b", "c")) // => { 1 => "a", 2 => "b", 3 => "c" }function zip<A, B>(LinkedList<A> a, LinkedList<B> b) returns LinkedList<Pair<A, B>>Creates a list of grouped elements, the first of which contains the first elements of the given lists, the second of which contains the second elements of the given lists.
let keys = asList(1, 2, 3) let values = asList("a", "b", "c") zip(keys, values) // => { 1 => "a", 2 => "b", 3 => "c" }function LinkedList<T>.uniq<T>() returns LinkedList<T>Creates a duplicate-free version of a list in which only the first occurrence of each element is kept. The order of result values is determined by the order they occur in the list. Example:
asList(1, 3, 2, 1, 4, 2, 5).uniq() // => [1, 3, 2, 4, 5]function LinkedList<T>.uniqBy<T, R>(Function<T, R> func) returns LinkedList<T>Creates a duplicate-free version of a list in which only the first occurrence of each element is kept as compared by func. The order of result values is determined by the order they occur in the list. The iteratee is invoked with one argument: (value). Example:
asList(1.0, 1.1, 1.2, 2.0, 2.1, 2.2).uniqBy(x -> x.floor()) // => [1.0, 2.0]function LinkedList<T>.union<T>(LinkedList<T> lst) returns LinkedList<T>Creates a list of unique values, in order, from the given lists. Example:
asList(1, 2, 3).union(asList(3, 4, 5)) // => [1, 2, 3, 4, 5]function LinkedList<T>.intersection<T>(LinkedList<T> lst) returns LinkedList<T>Creates an array of unique values that are included in both given lists. Example:
asList(1, 2, 3).intersection(asList(3, 4, 5)) // => [3]function LinkedList<T>.difference<T>(LinkedList<T> lst) returns LinkedList<T>Creates an array of array values not included in the other given lists. Example:
asList(1, 2, 3).difference(asList(3, 4, 5)) // => [1, 2]function LinkedList<T>.indexBy<T, R>(Function<T, R> idx) returns IterableMap<R, T>Creates an iterable map composed of keys generated from the results of running each element of collection thru iteratee. The corresponding value of each key is the last element responsible for generating the key. The iteratee is invoked with one argument: (value). Example:
let list = asList( pair(1, "a"), pair(2, "b"), pair(3, "c") ) list.indexBy(x -> x.b) // => { // "a" => pair(1, "a"), // "b" => pair(2, "b"), // "c" => pair(3, "c") // }function LinkedList<T>.groupBy<T, R>(Function<T, R> idx) returns IterableMap<R, LinkedList<T>>Creates an iterable map composed of keys generated from the results of running each element of collection thru iteratee. The order of grouped values is determined by the order they occur in collection. The corresponding value of each key is a list of elements responsible for generating the key. The iteratee is invoked with one argument: (value). Example:
let list = asList( pair(1, "a"), pair(2, "b"), pair(3, "c"), pair(4, "a"), pair(5, "c") ) list.groupBy(x -> x.b) // => { // "a" => [pair(1, "a"), pair(4, "a")], // "b" => [pair(2, "b")], // "c" => [pair(3, "c"), pair(5, "c")] // }function IterableMap<S, T>.mapValues<S, T, R>(BiFunction<S, T, R> transform) returns IterableMap<S, R>Creates an iterable map with the same keys as map and values generated by running each property of map thru iteratee. The iteratee is invoked with two arguments: (key, value). Example:
let map = makeMap( pair(1, "a"), pair(2, "b"), pair(3, "c") ) map.mapValues(x -> x.toUpperCase()) // => { // 1 => "A", // 2 => "B", // 3 => "C" // }function IterableMap<S, T>.mapKeys<S, T, R>(BiFunction<S, T, R> transform) returns IterableMap<R, T>Creates an iterable map with the same values as map and keys generated by running each key of map thru iteratee. The iteratee is invoked with two arguments: (key, value). Example:
let map = makeMap( pair(1, "a"), pair(2, "b"), pair(3, "c") ) map.mapValues(x -> x + 1) // => { // 2 => "a", // 3 => "b", // 4 => "c" // }function IterableMap<S, T>.toPairs<S, T>() returns LinkedList<Pair<S, T>>Converts an interable map to a list of pairs for each key, value pair. Example:
let map = makeMap( pair(1, "a"), pair(2, "b"), pair(3, "c") ) map.toPairs() // => [ // pair(1, "a"), // pair(2, "b"), // pair(3, "c") // ]function LinkedList<Pair<S, T>>.fromPairs<S, T>() returns IterableMap<S, T>Takes a list of key value pairs and transforms them into a iterable map. Example:
let map = asList( pair(1, "a"), pair(2, "b"), pair(3, "c") ) map.fromPairs() // => { // 1 => "a", // 2 => "b", // 3 => "c" // }function LinkedList<T>.chunk<T>(int size) returns LinkedList<LinkedList<T>>Creates a list of elements split into groups the length of size. If list can't be split evenly, the final chunk will be the remaining elements. Example:
asList(1, 2, 3, 4, 5, 6, 7, 8).chunk(3) // => [[1, 2, 3], [4, 5, 6], [7, 8]]function LinkedList<A>.product<A, B>(LinkedList<B> lst) returns LinkedList<Pair<A, B>>Creates a list containing pairs representing the Cartesian product of the two given lists.
asList(1, 2).product(asList(3, 4)) // => [pair(1, 3), pair(1, 4), pair(2, 3), pair(2, 4)]function LinkedList<T>.pull<T>(T pull) returns LinkedList<T>Removes all given values from list. Example:
asList(1, 2, 3, 4, 5, 4, 3, 2, 1).pull(3) // => [1, 2, 4, 5, 4, 2, 1]function LinkedList<T>.find<T>(Predicate<T> func) returns TReturns the first element matching the predicate function. Example:
asList(pair(1, "a"), pair(2, "b"), pair(3, "c"), pair(2, "d")).find(x -> x.a == 2) // => pair(2, "b")function LinkedList<T>.findLast<T>(Predicate<T> func) returns TReturns the last element matching the predicate function. Example:
asList(pair(1, "a"), pair(2, "b"), pair(3, "c"), pair(2, "d")).findLast(x -> x.a == 2) // => pair(2, "d")