Skip to content

Functions

Utility functions and building blocks for functional programming styles.

Functions

bind

function dash.bind(fn, ...) --> (...A2) -> R
Takes a function fn and binds arguments to the head of the fn argument list. Returns a function which executes fn, passing the bound arguments supplied, followed by any dynamic arguments.

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
Takes a chainable function fn and binds arguments to the tail of the fn argument list. Returns a function which executes fn, passing a subject ahead of the bound arguments supplied.

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


Chainable

call

function dash.call(subject, fn, ...) --> R
Calls the supplied fn on the subject and any additional arguments, returning the result.

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 type

fn - (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


Chainable

chain

function dash.chain(fns, actor) --> Chain<S, T>
Chain takes a dictionary of chainable functions and returns a Chain instance with methods mapped to the input functions.

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 type

actor - 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 writing dash.chain(_):filter you can simply write dash.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


chainFn

function dash.chainFn(fn) --> (T, ...A) -> R
Wraps a function, making it chainable if it returns a chain itself.

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


Chainable

compose

function dash.compose(...) --> (...A) -> A
Returns a function that calls the argument functions in left-right order on an input, passing the return of the previous function as argument(s) to the next.

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>
An Actor getter which awaits on any promises returned by chain methods, and continues execution when the promise completes.

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
Creates a debounced function that delays calling fn until after delayInSeconds seconds have elapsed since the last time the debounced function was attempted to be called.

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


Chainable

id

function dash.id(...) --> ...A
A simple function that does nothing, but returns its input parameters.

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
An Actor which calls the supplied fn with the argument tail.

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
Return 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>
An Actor which cancels execution of a chain if a method returns nil, evaluating the chain as nil.

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
Like dash.once, but caches non-nil results of calls to fn keyed by some serialization of the input arguments to fn. By default, all the args are serialized simply using 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


noop

function dash.noop() --> void
A simple function that does nothing, and returns nil.

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.

Chainable

once

function dash.once(fn) --> Clearable & (...A) -> R
Returns a function that when called, only calls fn the first time the function is called. For subsequent calls, the initial return of fn is returned, even if it is 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.

Chainable

returns

function dash.returns(...) --> (void) -> ...A
Returns a function that when called, returns the original input parameters.

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
Like dash.setTimeout but calls fn after every interval of intervalInSeconds time has passed.

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 number

delayInSeconds - 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
Like 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
Creates a throttle function that drops any repeat calls within a cooldown period and instead returns the result of the last call.

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

See


throws

function dash.throws(errorMessage) --> (void) -> fail
Returns a function that when called, throws the original message.

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
Returns a function that wraps the input fn but only passes the first argument to it.

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>
A Chain built from Rodash itself. Any Chainable Rodash function can be used as a method on this object, omitting the subject until the whole chain is evaluated by calling it with the subject.

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"}