Type: Package
Title: Functional Programming with Parallelism and Progress Tracking
Version: 0.5.0
Maintainer: Imad EL BADISY <elbadisyimad@gmail.com>
Description: Provides functional tools such as fmap(), fwalk(), and fapply() to iterate over vectors, data frames, or grouped data with optional parallelism and real-time progress tracking. Designed for readable and reproducible workflows, including support for Monte Carlo simulations and benchmarking.
License: MIT + file LICENSE
Encoding: UTF-8
Imports: parallel
Suggests: testthat (≥ 3.0.0), bench, rsample
Config/testthat/edition: 3
RoxygenNote: 7.3.2
BugReports: https://github.com/ielbadisy/functionals/issues
NeedsCompilation: no
Packaged: 2025-07-15 12:26:32 UTC; imad-el-badisy
Author: Imad EL BADISY [aut, cre]
Repository: CRAN
Date/Publication: 2025-07-18 15:00:08 UTC

functionals: Functional programming with parallelism and progress track in R

Description

This package provides a consistent and intuitive API for applying functions over lists, vectors, and data frames, with built-in support for parallelism and progress bars.

Author(s)

Maintainer: Imad EL BADISY elbadisyimad@gmail.com

See Also

Useful links:


Apply a function over a list or vector with optional parallelism and progress

Description

A lightweight and fast version of 'lapply()' with support for multicore (Unix) and snow-style clusters via 'parallel', with internal progress bar tracking and message suppression.

Usage

fapply(.x, .f, ncores = 1, pb = FALSE, cl = NULL, load_balancing = TRUE, ...)

Arguments

.x

A list or atomic vector.

.f

Function to apply.

ncores

Number of cores to use (default: 1 = sequential).

pb

Show progress bar? (default: FALSE).

cl

A cluster object (from parallel::makeCluster), or integer for core count.

load_balancing

Logical. Use 'parLapplyLB' if 'TRUE' (default: 'FALSE').

...

Additional arguments passed to '.f'.

Value

A list of results.

Examples

# Basic usage (sequential)
fapply(1:5, sqrt)

# With progress bar (sequential)
fapply(1:5, function(x) { Sys.sleep(0.1); x^2 }, pb = TRUE)

# Multicore on Unix (if available)

if (.Platform$OS.type != "windows") {
  fapply(1:10, sqrt, ncores = 2)
}


# With user-created cluster (portable across platforms)

cl <- parallel::makeCluster(2)
fapply(1:10, sqrt, cl = cl)
parallel::stopCluster(cl)


# Heavy computation example with chunked parallelism

heavy_fn <- function(x) { Sys.sleep(0.05); x^2 }
fapply(1:20, heavy_fn, ncores = 2, pb = TRUE)



Compose multiple functions

Description

Create a new function by composing several functions, applied from right to left. Equivalent to 'f1(f2(f3(...)))'.

Usage

fcompose(...)

Arguments

...

Functions to compose. Each must take a single argument and return an object compatible with the next function in the chain.

Value

A new function equivalent to nested application of the input functions.

Examples

square <- function(x) x^2
add1 <- function(x) x + 1

f <- fcompose(sqrt, square, add1)  # => sqrt(square(x + 1))
f(4)  # => sqrt((4 + 1)^2) = sqrt(25) = 5

# More compact
fcompose(log, exp)(2)  # log(exp(2)) = 2


Functional Cross-Validation mapping

Description

Applies a user-defined function '.f' to each element of '.splits', typically from cross-validation objects such as 'rsample::vfold_cv()'.

Usage

fcv(.splits, .f, ncores = NULL, pb = FALSE, ...)

Arguments

.splits

A list of resample splits (e.g., from 'rsample::vfold_cv()').

.f

A function to apply to each split. Typically expects a single 'split' object.

ncores

Integer. Number of cores to use for parallel processing. Default is 'NULL' (sequential).

pb

Logical. Whether to display a progress bar. Default is 'FALSE'.

...

Additional arguments passed to '.f'.

Value

A list of results returned by applying '.f' to each element of '.splits'.

Examples

if (requireNamespace("rsample", quietly = TRUE)) {
  set.seed(123)
  cv_splits <- rsample::vfold_cv(mtcars, v = 5)

  # Apply summary over training sets
  fcv(cv_splits$splits, function(split) {
    summary(rsample::analysis(split))
  })

  # With progress and parallel execution
  
    fcv(cv_splits$splits, function(split) {
      summary(rsample::analysis(split))
    }, ncores = 2, pb = TRUE)
  
}


Functional loop with optional parallelism and progress bar

Description

'floop()' applies a function '.f' to each element of '.x', optionally in parallel, and with an optional progress bar. Unlike 'fwalk()', it can return results or be used purely for side effects (like a for-loop).

Usage

floop(.x, .f, ncores = 1, pb = FALSE, .capture = TRUE, ...)

Arguments

.x

A vector or list of elements to iterate over.

.f

A function to apply to each element of '.x'.

ncores

Integer. Number of cores to use. Default is 1 (sequential).

pb

Logical. Show a progress bar? Default is 'FALSE'.

.capture

Logical. Should results of '.f' be captured and returned? If 'FALSE', acts like a side-effect loop.

...

Additional arguments passed to '.f'.

Value

A list of results if '.capture = TRUE', otherwise returns '.x' invisibly.

Examples

# Functional loop that collects output
floop(1:3, function(i) i^2)

# Side-effect only loop (like for-loop with cat)

floop(1:5, function(i) cat(" Processing", i, "\n"), pb = TRUE, .capture = FALSE)



Functional mapping with optional parallelism and progress bars

Description

Applies a function '.f' to each element of '.x', with optional parallel processing and progress bar support.

Usage

fmap(.x, .f, ncores = NULL, pb = FALSE, ...)

Arguments

.x

A list or atomic vector of elements to iterate over.

.f

A function to apply to each element of '.x'. Can be a function or a string naming a function.

ncores

Integer. Number of CPU cores to use for parallel processing. Default is 'NULL' (sequential).

pb

Logical. Whether to show a progress bar. Default is 'FALSE'.

...

Additional arguments passed to '.f'.

Value

A list of results, one for each element of '.x'.

Examples

slow_fn <- function(x) { Sys.sleep(0.01); x^2 }
x <- 1:100

# Basic usage
fmap(x, slow_fn)

# With progress bar
fmap(x, slow_fn, pb = TRUE)

# With parallel execution (non-Windows)

if (.Platform$OS.type != "windows") {
  fmap(x, slow_fn, ncores = 2, pb = TRUE)
}



Apply a function column-wise with name access and parallelism

Description

Applies a function '.f' to each column of a data frame '.df'. Each call receives both the column vector and its name, enabling name-aware column processing. Supports parallel execution and progress display.

Usage

fmapc(.df, .f, ncores = NULL, pb = FALSE, ...)

Arguments

.df

A data frame whose columns will be iterated over.

.f

A function that takes two arguments: the column vector and its name.

ncores

Integer. Number of cores to use for parallel processing. Default is 'NULL' (sequential).

pb

Logical. Whether to display a progress bar. Default is 'FALSE'.

...

Additional arguments passed to '.f'.

Value

A list of results obtained by applying '.f' to each column of '.df'.

Examples

df <- data.frame(a = 1:3, b = 4:6)

# Apply a function that returns column mean and name
fmapc(df, function(x, name) list(mean = mean(x), var = var(x), name = name))

# With progress and parallel execution

fmapc(df, function(x, name) mean(x), ncores = 2, pb = TRUE)



Apply a function to groups of a data frame in parallel

Description

Applies a function '.f' to each group of rows in a data frame '.df', where grouping is defined by one or more variables in 'by'. Each group is passed as a data frame to '.f'. Supports parallelism and optional progress display.

Usage

fmapg(.df, .f, by, ncores = NULL, pb = FALSE, ...)

Arguments

.df

A data frame to group and apply the function over.

.f

A function to apply to each group. The function should accept a data frame (a group).

by

A character vector of column names in '.df' used for grouping.

ncores

Integer. Number of cores to use for parallel processing. Default is 'NULL' (sequential).

pb

Logical. Whether to show a progress bar. Default is 'FALSE'.

...

Additional arguments passed to '.f'.

Value

A list of results, one for each group defined by 'by'.

Examples

# Group-wise mean of Sepal.Length in iris dataset
fmapg(iris, function(df) mean(df$Sepal.Length), by = "Species")

# Group-wise model fitting with progress and parallelism

fmapg(mtcars, function(df) lm(mpg ~ wt, data = df), by = "cyl", ncores = 2, pb = TRUE)



Apply a function over multiple argument lists in parallel

Description

Applies a function '.f' over multiple aligned lists in '.l'. Each element of '.l' should be a list or vector of the same length. Each call to '.f' receives one element from each list. Supports parallel execution and progress display.

Usage

fmapn(.l, .f, ncores = NULL, pb = FALSE, ...)

Arguments

.l

A list of vectors or lists. All elements must be of equal length.

.f

A function to apply. It must accept as many arguments as there are elements in '.l'.

ncores

Integer. Number of cores to use for parallel processing. Default is 'NULL' (sequential).

pb

Logical. Whether to display a progress bar. Default is 'FALSE'.

...

Additional arguments passed to '.f'.

Value

A list of results obtained by applying '.f' to each tuple from '.l'.

Examples

# Fit a linear model for each response variable using the same predictor
df <- data.frame(
  y1 = rnorm(100),
  y2 = rnorm(100),
  x = rnorm(100)
)

# List of formulas and data
formulas <- list(y1 ~ x, y2 ~ x)
data_list <- list(df, df)

fmapn(list(formula = formulas, data = data_list), function(formula, data) {
  lm(formula, data = data)
})

# Extract model summaries in parallel
models <- fmapn(list(formula = formulas, data = data_list), function(formula, data) {
  summary(lm(formula, data = data))$r.squared
})


Apply a function row-wise on a data frame with parallelism

Description

Applies a function '.f' to each row of a data frame '.df', with optional parallelism and progress bar. Each row is converted to a named list before being passed to '.f', enabling flexible access to variables by name.

Usage

fmapr(.df, .f, ncores = NULL, pb = FALSE, ...)

Arguments

.df

A data frame whose rows will be iterated over.

.f

A function applied to each row, which receives a named list.

ncores

Integer. Number of cores to use for parallel processing. Default is 'NULL' (sequential).

pb

Logical. Whether to display a progress bar. Default is 'FALSE'.

...

Additional arguments passed to '.f'.

Value

A list of results returned by applying '.f' to each row as a list.

Examples

df <- data.frame(name = c("Mister", "Hipster"), age = c(30, 25))

# Create personalized messages
fmapr(df, function(row) paste(row$name, "is", row$age, "years old"))

# Row-wise model formulas
formulas <- data.frame(
  response = c("y1", "y2"),
  predictor = c("x1", "x2"),
  stringsAsFactors = FALSE
)

fmapr(formulas, function(row) {
  reformulate(row$predictor, row$response)
})


Functional reduce

Description

Apply a binary function iteratively over a list or vector, reducing it to a single value or a sequence of intermediate results. This is a wrapper around [Reduce()] that supports optional initial values, right-to-left evaluation, accumulation of intermediate steps, and output simplification.

Usage

freduce(
  .x,
  .f,
  .init = NULL,
  .right = FALSE,
  .accumulate = FALSE,
  .simplify = TRUE
)

Arguments

.x

A vector or list to reduce.

.f

A binary function to apply. Can be given as a function or quoted (e.g., '\'+\“).

.init

Optional initial value passed to [Reduce()]. If 'NULL', reduction starts from the first two elements.

.right

Logical. If 'TRUE', reduction is performed from right to left.

.accumulate

Logical. If 'TRUE', returns a list of intermediate results (like a scan).

.simplify

Logical. If 'TRUE' and all intermediate results are length 1, the output is simplified to a vector.

Value

A single value (default) or a list/vector of intermediate results if '.accumulate = TRUE'.

Examples

freduce(1:5, `+`)                          # => 15
freduce(letters[1:4], paste0)             # => "abcd"
freduce(list(1, 2, 3), `*`)               # => 6
freduce(1:3, `+`, .init = 10)             # => 16
freduce(1:3, paste0, .right = TRUE)       # => "321"
freduce(1:4, `+`, .accumulate = TRUE)     # => c(1, 3, 6, 10)


Repeat an expression or function call multiple times

Description

Repeats an expression or function evaluation 'times' times. If 'expr' is a function, it is invoked with optional input '.x' and additional arguments. If 'expr' is a quoted expression, it is evaluated in the parent environment. Supports parallel processing and optional simplification of results.

Usage

frepeat(
  .x = NULL,
  times,
  expr,
  simplify = FALSE,
  ncores = NULL,
  pb = FALSE,
  ...
)

Arguments

.x

Optional input passed to 'expr' if 'expr' is a function. Default is 'NULL'.

times

Integer. Number of repetitions.

expr

A function or an unevaluated expression to repeat. If a function, it will be called 'times' times.

simplify

Logical. If 'TRUE', attempts to simplify the result using 'simplify2array()'. Default is 'FALSE'.

ncores

Integer. Number of cores to use for parallel execution. Default is 'NULL' (sequential).

pb

Logical. Whether to display a progress bar. Default is 'FALSE'.

...

Additional arguments passed to the function 'expr' if it is callable.

Value

A list of outputs (or a simplified array if 'simplify = TRUE') from evaluating 'expr' multiple times.

Note

If 'expr' is passed as a function call (not a function or quoted expression), it will be evaluated immediately, not repeated. Use function(...) \{ ... \} or quote(...) instead.

Examples

# Repeat a pure function call
frepeat(times = 3, expr = function() rnorm(1))

# Repeat a function with input `.x`
frepeat(.x = 10, times = 3, expr = function(x) rnorm(1, mean = x))

# Repeat an unevaluated expression (evaluated with `eval()`)
frepeat(times = 2, expr = quote(rnorm(1)))

# Simplify the output to an array
frepeat(times = 3, expr = function() rnorm(1), simplify = TRUE)

# Monte Carlo simulation: estimate coverage of a 95% CI for sample mean
mc_result <- frepeat(times = 1000, simplify = TRUE, pb = TRUE, ncores = 1, expr = function() {
  sample <- rnorm(30, mean = 0, sd = 1)
  ci <- t.test(sample)$conf.int
  mean(ci[1] <= 0 & 0 <= ci[2])  # check if true mean is inside the interval
})
mean(mc_result)  # estimated coverage


Walk over a vector or list with side effects

Description

Applies a function '.f' to each element of '.x', typically for its side effects (e.g., printing, writing files). This function is the side-effect-friendly equivalent of 'fmap()'. Supports parallel execution and progress bar display.

Usage

fwalk(.x, .f, ncores = NULL, pb = FALSE, ...)

Arguments

.x

A list or atomic vector of elements to iterate over.

.f

A function to apply to each element of '.x'. Should be called primarily for side effects.

ncores

Integer. Number of cores to use for parallel processing. Default is 'NULL' (sequential).

pb

Logical. Whether to show a progress bar. Default is 'FALSE'.

...

Additional arguments passed to '.f'.

Value

Invisibly returns '.x', like 'purrr::walk()'.

Examples

# Print each element
fwalk(1:3, print)

# Simulate writing files in parallel

fwalk(1:3, function(i) {
  cat(paste("Processing item", i, "\n"))
  Sys.sleep(0.5)
}, ncores = 2, pb = TRUE)