Functions¶
Utility functions and building blocks for functional programming styles.
Functions¶
bind¶
function dash.bind(fn, ...) --> (...A2) -> R
Type
<A, A2, R>(((...A, ...A2 -> R), ...A) -> ...A2 -> R)
Generics
A -
any
- the primary arguments (extends any value)A2 -
any
- the secondary arguments (extends any value)R -
any
- the result type (extends any value)
Parameters
fn -
(...A, ...A2) -> R
- a function (taking the primary arguments and the secondary arguments, and returning the result type)... -
...A
- the primary arguments
Returns
(...A2) -> R
- a function (taking the secondary arguments, and returning the result type)
Examples
local function damagePlayer( player, amount ) player:Damage(amount) end local damageLocalPlayer = dash.bind(damagePlayer, game.Players.LocalPlayer) damageLocalPlayer(5)
bindTail¶
function dash.bindTail(fn, ...) --> (S) -> S
Type
<S>(Chainable<S>, ...) -> S -> S
Generics
S -
any
- the subject type (extends any value)
Parameters
fn -
Chainable<S>
- a Chainable (of the subject type)... -
...any
- any values
Returns
(S) -> S
- a function (taking the subject type, and returning the subject type)
Examples
local function setHealthTo(player, health) player.Health = health end local restoreHealth = dash.bindTail(setHealthTo, 100) local Jimbo = { Health = 5 } restoreHealth(Jimbo) Jimbo.Health --> 100
local filterHurtPlayers = dash.bindTail(dash.filter, function(player) return player.Health < player.MaxHealth end) local getName = dash.bindTail(dash.map, function(player) return player.Name end) local filterHurtNames = dash.compose(filterHurtPlayers, getName) filterHurtNames(game.Players) --> {"Frodo", "Boromir"}
Usage
- Chainable rodash function feeds are mapped to dash.fn, such as
dash.fn.map(handler)
.
See
call¶
function dash.call(subject, fn, ...) --> R
Type
<S, A, R>(S, (S, ...A -> R), ...A -> R)
Generics
S -
any
- the subject type (extends any value)A -
any
- the primary arguments (extends any value)R -
any
- the result type (extends any value)
Parameters
subject -
S
- the subject typefn -
(S, ...A) -> R
- a function (taking the subject type and the primary arguments, and returning the result type)... -
...A
- the primary arguments
Returns
R
- the result type
Examples
local function get(object, key) return object[key] end local Jimbo = { Name = "Jimbo" } dash.call(Jimbo, get, "Name") --> "Jimbo"
local function get(object, key) return object[key] end local isABaggins = dash.fn:call(get, "Name"):endsWith("Baggins") local Jimbo = { Name = "Jimbo" } isABaggins(Jimbo) --> false
Usage
- This is useful when used in the
dash.fn:call
form to call arbitrary function inside a chain.
See
chain¶
function dash.chain(fns, actor) --> Chain<S, T>
Chaining is useful when you want to simplify operating on data in a common form and perform sequences of operations on some data with a very concise syntax. An actor function can check the value of the data at each step and change how the chain proceeds.
Calling a Chain with a subject reduces the chained operations in order on the subject.
Type
<S,T:Chainable<S>{}>(T, Actor<S>) -> Chain<S,T>
Generics
S -
any
- the subject type (extends any value)T -
Chainable<S>{}
- the primary type (extends a dictionary (of Chainables (of the subject type)))
Parameters
fns -
T
- the primary typeactor -
Actor<S>
- an Actor (of the subject type) - called for each result in the chain to determine how the next operation should process it. (default = dash.invoke)
Returns
Chain<S, T>
- a Chain (of the subject type and the primary type)
Examples
-- Define a simple chain that can operate a list of numbers. -- A chain function is called with the subject being processed as first argument, -- and any arguments passed in the chain as subsequent arguments. local numberChain = dash.chain({ addN = function(list, n) return dash.map(list, function(element) return element + n end) end, sum = function(list) return dash.sum(list) end }) local op = numberChain:addN(2):sum() op({1, 2, 3}) --> 12
-- Get the name of a player local function getName(player) return player.Name end) -- Create a chain that filters for hurt players and finds their name local filterHurtNames = dash.fn:filter(function(player) return player.Health < player.MaxHealth end):map(getName) -- Run the chain on the current game players filterHurtNames(game.Players) --> {"Frodo Baggins", "Boromir"} -- For fun, let's encapsulate the functionality above by -- defining a chain of operations on players... local players = dash.chain({ filterHurtPlayers = dash.fn:filter(function(player) return player.Health < player.MaxHealth end), -- Filter players by getting their name and checking it ends with 'Baggins' filterBaggins = dash.fn:filter(dash.fn:call(getName):endsWith("Baggins")) }) local hurtHobbits = players:filterHurtPlayers():filterBaggins() hurtHobbits(game.Players) --> {{Name = "Frodo Baggins", ...}} local names = dash.fn:map(getName) -- Chains are themselves chainable, so you can compose two chains together local filterHurtHobbitNames = dash.compose(hurtHobbits, names) filterHurtHobbitNames(game.Players) --> {"Frodo Baggins"}
Usage
-
The "Rodash" chain:
dash.chain(_)
is aliased to dash.fn, so instead of writingdash.chain(_):filter
you can simply writedash.fn:filter
, or any other chainable method. -
A chained function can be made using dash.chain or built inductively using other chained methods of dash.fn.
-
A chainable method is one that has the subject which is passed through a chain as the first argument, and subsequent arguments
See
-
dash.chainFn - Makes a function chainable if it returns a chain.
-
dash.invoke - the identity actor
-
dash.continue - an actor for chains of asynchronous functions
-
dash.maybe - an actor for chains of partial functions
chainFn¶
function dash.chainFn(fn) --> (T, ...A) -> R
This allows you to define custom functions in terms of the arguments they will take when called in a chain, and return a chained function which performs the operation, rather than explicitly taking the subject as first argument.
Type
<T, A, R>((...A -> T -> R) -> T, ...A -> R)
Generics
T -
any
- the primary type (extends any value)A -
any
- the primary arguments (extends any value)R -
any
- the result type (extends any value)
Parameters
fn -
(...A) -> (T) -> R
- a function (taking the primary arguments, and returning a function (taking the primary type, and returning the result type))
Returns
(T, ...A) -> R
- a function (taking the primary type and the primary arguments, and returning the result type)
Examples
-- In the chain example addN was defined like so: local function addN(list, n) return dash.map(list, function(element) return element + n end) end numberChain = dash.chain({ addN = addN }) local op = numberChain:addN(2):sum() op({1, 2, 3}) --> 12 -- It is more natural to define addN as a function taking one argument, -- to match the way it is called in the chain: local function addN(n) -- Methods on dash.fn are themselves chained, so "list" can be dropped. return dash.fn:map(function(element) return element + n end) end -- The dash.chainFn is used to wrap any functions which return chains. numberChain = dash.chain({ addN = dash.chainFn(addN) }) local op = numberChain:addN(2):sum() op({1, 2, 3}) --> 12
See
compose¶
function dash.compose(...) --> (...A) -> A
Type
<A>((...A -> ...A)[]) -> ...A -> A
Generics
A -
any
- the primary arguments (extends any value)
Parameters
... -
(...A) -> ...A[]
- an array (of functions (taking the primary arguments, and returning the primary arguments))
Returns
(...A) -> A
- a function (taking the primary arguments, and returning the primary arguments)
Examples
local function fry(item) return "fried " .. item end local function cheesify(item) return "cheesy " .. item end local prepare = dash.compose(fry, cheesify) prepare("nachos") --> "cheesy fried nachos"
Usage
- Useful for when you want to lazily compute something expensive that doesn't change.
continue¶
function dash.continue(actor) --> Actor<S>
This allows any asynchronous methods to be used in chains without modifying any of the chain's synchronous methods, removing any boilerplate needed to handle promises in the main code body.
Can wrap any other actor which handles values after any promise resolution.
Type
<S>(Actor<S>? -> Actor<S>)
Generics
S -
any
- the subject type (extends any value)
Parameters
actor -
Actor<S>?
- an Actor (of the subject type) (optional) - (default = dash.invoke) The actor to wrap.
Returns
Actor<S>
- an Actor (of the subject type)
Rejects
- passthrough - The returned promise will reject if promises passed as arguments reject.
Examples
-- Let's define a function which returns an answer after a delay local getName = function(player) return dash.delay(1):andThen(dash.returns(player.Name)) end local players players = dash.chain( { -- Any chainable function can be used filter = dash.filter, -- A chain which evaluates a promise of the player names mapNames = dash.fn:map(getName):parallel(), filterHurt = dash.fn:filter( function(player) return player.Health < 100 end ), mapNameIf = dash.chainFn( function(expectedName) -- Methods on self work as expected return players:mapNames():filter(dash.fn:endsWith(expectedName)) end ) }, dash.continue() ) local filterHurtHobbitNames = players:filterHurt():mapNameIf("Baggins") local crew = { { Name = "Frodo Baggins", Health = 50 }, { Name = "Bilbo Baggins", Health = 100 }, { Name = "Boromir", Health = 0 } } filterHurtHobbitNames(crew):await() --> {"Frodo Baggins"} (some time later)
See
debounce¶
function dash.debounce(fn, delayInSeconds) --> Clearable & (...A) -> R
Type
<A, R>(...A -> R), number -> Clearable & (...A -> R)
Generics
A -
any
- the primary arguments (extends any value)R -
any
- the result type (extends any value)
Parameters
fn -
(...A) -> R
- a function (taking the primary arguments, and returning the result type)delayInSeconds -
number
- a number
Returns
Clearable & (...A) -> R
- an intersection (of a Clearable and a function (taking the primary arguments, and returning the result type)) - the debounced function with method:clear()
can be called on to cancel any scheduled call.
Usage
- A nice visualisation of debounce vs. throttle, the illustrated point being debounce will only call fn at the end of a spurt of events.
id¶
function dash.id(...) --> ...A
Type
<A>(...A -> ...A)
Generics
A -
any
- the primary arguments (extends any value)
Parameters
... -
...A
- the primary arguments
Returns
...A
- the primary arguments
Usage
- This is typically referred to as the "identity" function. Useful for when a function is expecting a callback to transform a value but you don't want to make any change to it.
invoke¶
function dash.invoke(fn, ...) --> S
Type
<S, A>((A -> S), ...A -> S)
Generics
S -
any
- the subject type (extends any value)A -
any
- the primary arguments (extends any value)
Parameters
fn -
(A) -> S
- a function (taking the primary arguments, and returning the subject type)... -
...A
- the primary arguments
Returns
S
- the subject type
Examples
local getName = function(player) return player.Name end local Jimbo = { Name = "Jimbo" } dash.invoke(getName, Jimbo) --> "Jimbo"
Usage
- This is the default actor for dash.chain and acts as an identity, meaning it has no effect on the result.
isCallable¶
function dash.isCallable(value) --> bool
true
if the value is a function or a table with a __call
entry in its metatable.
Type
any -> bool
Parameters
value -
any
- any value
Returns
bool
- a boolean
Usage
- This is a more general test than checking purely for a function type.
maybe¶
function dash.maybe(actor) --> Actor<S>
Can wrap any other actor which handles values that are non-nil.
Type
<S>(Actor<S>? -> Actor<S>)
Generics
S -
any
- the subject type (extends any value)
Parameters
actor -
Actor<S>?
- an Actor (of the subject type) (optional)
Returns
Actor<S>
- an Actor (of the subject type)
Examples
-- We can define a chain of Rodash functions that will skip after a nil is returned. local maybeFn = dash.chain(_, dash.maybe()) local getName = function(player) return player.Name end local players players = dash.chain( { -- Any chainable functions can be used call = dash.call, endsWith = dash.endsWith, filterHurt = dash.fn:filter( function(player) return player.Health < 100 end ), filterBaggins = dash.chainFn( function() -- If getName returns nil here, endsWith will be skipped return dash.fn:filter(maybeFn:call(getName):endsWith("Baggins")) end ) } ) local hurtHobbits = players:filterHurt():filterBaggins() local mapNames = dash.fn:map(getName) local filterHurtBagginsNames = dash.compose(hurtHobbits, mapNames) -- Here, one player record doesn't have a Name property, so it is skipped. local crew = { { Name = "Frodo Baggins", Health = 50 }, { Name = "Bilbo Baggins", Health = 100 }, { Health = 0 } }
memoize¶
function dash.memoize(fn, serializeArgs) --> Clearable<A> & AllClearable & (...A) -> R
tostring
.
Optionally memoize takes function serializeArgs(args, cache)
, a function that should return a string key which a
result should be cached at for a given signature. Return nil to avoid caching the result.
Type
<A, R>((...A -> R), ...A -> string?) -> Clearable<A> & AllClearable & (...A -> R)
Generics
A -
any
- the primary arguments (extends any value)R -
any
- the result type (extends any value)
Parameters
fn -
((...A) -> R, ...A) -> string?
- a function (taking a function (taking the primary arguments, and returning the result type) and the primary arguments, and returning a string (optional))serializeArgs -
any
- any value - (default = dash.serialize)
Returns
Clearable<A> & AllClearable & (...A) -> R
- an intersection (of a Clearable (of the primary arguments), an AllClearable and a function (taking the primary arguments, and returning the result type)) - the function with method:clear(...)
that resets the cache for the argument specified, or:clearAll()
to clear the entire cache.
Examples
local menu = {"soup", "bread", "butter"} local heat = dash.memoize(function(index) return "hot " ... menu[index] end) heat(1) --> "hot soup" menu = {"caviar"} heat(1) --> "hot soup" heat(2) --> nil menu = {"beef", "potatoes"} heat(1) --> "hot soup" heat(2) --> "hot potatoes" heat:clear(1) heat(1) --> "hot beef"
See
-
dash.serializeDeep if you want to recursively serialize arguments.
noop¶
function dash.noop() --> void
Type
() -> ()
Returns
void
- nothing
Usage
- Shorthand for
function() end
. Useful for when a function is expecting a callback but you don't want to do anything.
once¶
function dash.once(fn) --> Clearable & (...A) -> R
nil
.
Type
<A, R>((...A -> R), R?) -> Clearable & (...A -> R)
Generics
A -
any
- the primary arguments (extends any value)R -
any
- the result type (extends any value)
Parameters
fn -
(...A) -> R
- a function (taking the primary arguments, and returning the result type)
Returns
Clearable & (...A) -> R
- an intersection (of a Clearable and a function (taking the primary arguments, and returning the result type)) - the function with method:clear()
that resets the cached value.
Throws
- passthrough - any error thrown when called will cause
nil
to cache and pass through the error.
Examples
local fry = dash.once(function(item) return "fried " .. item end) fry("sardine") --> "fried sardine" fry("squid") --> "fried sardine" fry:clear() fry("squid") --> "fried squid" fry("owl") --> "fried squid"
Usage
- Useful for when you want to lazily compute something expensive that doesn't change.
returns¶
function dash.returns(...) --> (void) -> ...A
Type
<A>(...A -> () -> ...A)
Generics
A -
any
- the primary arguments (extends any value)
Parameters
... -
...A
- the primary arguments
Returns
(void) -> ...A
- a function (taking nothing, and returning the primary arguments)
Examples
findPlayer("builderman"):andThen(dash.returns("Found Dave!")) --> "Found Dave!" (soon after)
Usage
- Useful for when you want a callback to discard the arguments passed in and instead use static ones.
setInterval¶
function dash.setInterval(fn, intervalInSeconds, delayInSeconds) --> Clearable
The fn is called in a separate thread, meaning that it will not block the thread it is called in, and if the calling threads, the fn will still be called at the expected times.
Type
(Clearable -> ()), number, number? -> Clearable
Parameters
fn -
(Clearable) -> void
- a function (taking a Clearable, and returning nothing)intervalInSeconds -
number
- a numberdelayInSeconds -
number?
- a number (optional) - (default = intervalInSeconds) The delay before the initial call.
Returns
Clearable
- a Clearable - an instance which:clear()
can be called on to prevent fn from firing.
Examples
local waitInterval = dash.setInterval(function() print("Waiting for more players...") end, 5) game.Players.PlayerAdded:Connect(function(player) waitInterval:clear() end)
See
setTimeout¶
function dash.setTimeout(fn, delayInSeconds) --> Clearable
delay
, this calls fn after delayInSeconds time has passed, with the added benefit of being cancelable.
The fn is called in a separate thread, meaning that it will not block the thread it is called in, and if the calling threads, the fn will still be called at the expected time.
Type
(Clearable -> ()), number -> Clearable
Parameters
fn -
(Clearable) -> void
- a function (taking a Clearable, and returning nothing)delayInSeconds -
number
- a number
Returns
Clearable
- a Clearable - an instance which:clear()
can be called on to prevent fn from firing.
Examples
local waitTimeout = dash.setTimeout(function() print("Sorry, no players came online!") end, 5) game.Players.PlayerAdded:Connect(function(player) waitTimeout:clear() end)
See
throttle¶
function dash.throttle(fn, cooldownInSeconds) --> (...A) -> R
Type
<A, R>((...A) -> R), number -> ...A -> R
Generics
A -
any
- the primary arguments (extends any value)R -
any
- the result type (extends any value)
Parameters
fn -
(...A) -> R
- a function (taking the primary arguments, and returning the result type)cooldownInSeconds -
number
- a number
Returns
(...A) -> R
- a function (taking the primary arguments, and returning the result type)
Examples
local post = dash.async(HttpService.Post) local saveMap = dash.throttle(function(data) post("https://example.com/save", data) end, 10) saveMap(map) -- This saves the map saveMap(map) -- This function call is throttled and won't result in post being called saveMap(map) -- Same again wait(10) saveMap(map) -- Enough time has passed, so this saves the map again
Usage
- A nice visualisation of debounce vs. throttle, the illustrated point being throttle will call fn every period during a spurt of events.
See
throws¶
function dash.throws(errorMessage) --> (void) -> fail
Type
string -> () -> fail
Parameters
errorMessage -
string
- a string
Returns
(void) -> fail
- a function (taking nothing, and returning a failure state)
Examples
findPlayer("builderman"):andThen(dash.throws("DaveNotFound")) --!> "DaveNotFound" (soon after)
Usage
- Useful for when you want a callback to discard any result and throw a message instead.
unary¶
function dash.unary(fn) --> (A) -> R
Type
<A, R>((A -> R) -> A -> R)
Generics
A -
any
- the primary arguments (extends any value)R -
any
- the result type (extends any value)
Parameters
fn -
(A) -> R
- a function (taking the primary arguments, and returning the result type)
Returns
(A) -> R
- a function (taking the primary arguments, and returning the result type)
Examples
local printOneArgument = dash.unary(function(...) print(...) end) printOneArgument("Hello", "World", "!") -->> Hello
Members¶
fn¶
dash.fn -- Chain<any,dash>
Examples
local getNames = dash.fn:map(function( player ) return player.Name end) getNames(game.Players) --> {"Bilbo Baggins", "Frodo Baggins", "Peregrin Took"}
local getNames = dash.fn:map(function( player ) return player.Name end):filter(function( name ) return dash.endsWith(name, "Baggins") end) getNames(game.Players) --> {"Bilbo Baggins", "Frodo Baggins"}
local getNames = dash.fn:map(function( player ) return player.Name end):filter(dash.fn:endsWith("Baggins")) getNames(game.Players) --> {"Bilbo Baggins", "Frodo Baggins"}