The goals of foreman are to:
Given these goals it is important to state that this package is not meant to replace any parent package.
The package supports both local packages and compiled libraries.
remotes::install_github("yonicd/foreman")
This example will use a local fork of purrr
.
library(foreman)
library(ggraph)
library(igraph)
Unpack a pacakge into a list
x <- unpack(path = '../forks/purrr/R', warn = FALSE)
Click the triangle to view the contents found in arrays.R
details::details(lapply(x$arrays.R,get_text),summary = 'arrays.R')
arrays.R
$array_branch
[1] "#' Coerce array to list"
[2] "#'"
[3] "#' `array_branch()` and `array_tree()` enable arrays to be"
[4] "#' used with purrr's functionals by turning them into lists. The"
[5] "#' details of the coercion are controlled by the `margin`"
[6] "#' argument. `array_tree()` creates an hierarchical list (a tree)"
[7] "#' that has as many levels as dimensions specified in `margin`,"
[8] "#' while `array_branch()` creates a flat list (by analogy, a"
[9] "#' branch) along all mentioned dimensions."
[10] "#'"
[11] "#' When no margin is specified, all dimensions are used by"
[12] "#' default. When `margin` is a numeric vector of length zero, the"
[13] "#' whole array is wrapped in a list."
[14] "#' @param array An array to coerce into a list."
[15] "#' @param margin A numeric vector indicating the positions of the"
[16] "#' indices to be to be enlisted. If `NULL`, a full margin is"
[17] "#' used. If `numeric(0)`, the array as a whole is wrapped in a"
[18] "#' list."
[19] "#' @name array-coercion"
[20] "#' @export"
[21] "#' @examples"
[22] "#' # We create an array with 3 dimensions"
[23] "#' x <- array(1:12, c(2, 2, 3))"
[24] "#'"
[25] "#' # A full margin for such an array would be the vector 1:3. This is"
[26] "#' # the default if you don't specify a margin"
[27] "#'"
[28] "#' # Creating a branch along the full margin is equivalent to"
[29] "#' # as.list(array) and produces a list of size length(x):"
[30] "#' array_branch(x) %>% str()"
[31] "#'"
[32] "#' # A branch along the first dimension yields a list of length 2"
[33] "#' # with each element containing a 2x3 array:"
[34] "#' array_branch(x, 1) %>% str()"
[35] "#'"
[36] "#' # A branch along the first and third dimensions yields a list of"
[37] "#' # length 2x3 whose elements contain a vector of length 2:"
[38] "#' array_branch(x, c(1, 3)) %>% str()"
[39] "#'"
[40] "#' # Creating a tree from the full margin creates a list of lists of"
[41] "#' # lists:"
[42] "#' array_tree(x) %>% str()"
[43] "#'"
[44] "#' # The ordering and the depth of the tree are controlled by the"
[45] "#' # margin argument:"
[46] "#' array_tree(x, c(3, 1)) %>% str()"
[47] "array_branch <- function(array, margin = NULL) {"
[48] " dims <- dim(array) %||% length(array)"
[49] " margin <- margin %||% seq_along(dims)"
[50] ""
[51] " if (length(margin) == 0) {"
[52] " list(array)"
[53] " } else if (is.null(dim(array))) {"
[54] " if (!identical(as.integer(margin), 1L)) {"
[55] " abort(sprintf("
[56] " \"`margin` must be `NULL` or `1` with 1D arrays, not `%s`\","
[57] " toString(margin)"
[58] " ))"
[59] " }"
[60] " as.list(array)"
[61] " } else {"
[62] " flatten(apply(array, margin, list))"
[63] " }"
[64] "}"
$array_tree
[1] "#' @rdname array-coercion"
[2] "#' @export"
[3] "array_tree <- function(array, margin = NULL) {"
[4] " dims <- dim(array) %||% length(array)"
[5] " margin <- margin %||% seq_along(dims)"
[6] ""
[7] " if (length(margin) > 1) {"
[8] " new_margin <- ifelse(margin[-1] > margin[[1]], margin[-1] - 1, margin[-1])"
[9] " apply(array, margin[[1]], array_tree, new_margin)"
[10] " } else {"
[11] " array_branch(array, margin)"
[12] " }"
[13] "}"
x_rel <- relationship(x)
Relationships contained in arrays.R
x_rel$arrays.R
#> $array_branch
#> [1] "flatten"
#>
#> $array_tree
#> [1] "array_branch"
Functions that compose
calls
relationship(x,parent = 'compose')
#> $compose.R
#> $compose.R$compose
#> [1] "compose" "map" "fn"
#>
#>
#> attr(,"class")
#> [1] "relationship" "list"
Functions who call flatten
relationship(x,child = 'flatten')
#> $arrays.R
#> $arrays.R$array_branch
#> [1] "flatten"
#>
#>
#> $lmap.R
#> $lmap.R$lmap_at
#> [1] "flatten"
#>
#>
#> $splice.R
#> $splice.R$splice_if
#> [1] "flatten"
#>
#>
#> attr(,"class")
#> [1] "relationship" "list"
x_rel_df <- as.data.frame(x_rel)
Click the triangle to view the data.frame
details::details(x_rel_df,summary = 'Relatives')
Relatives
child parent file
1 flatten array_branch arrays.R
2 as_mapper as_function as_mapper.R
3 stop_defunct as_function as_mapper.R
4 paste_line as_function as_mapper.R
5 coerce coerce_lgl coerce.R
6 can_simplify as_vector coercion.R
7 warn_deprecated signal_soft_deprecated compat-lifecycle.R
8 compose compose compose.R
9 map compose compose.R
10 fn compose compose.R
11 as_vector lift_vl composition.R
12 what_bad_object stop_bad_type conditions.R
13 friendly_type_of stop_bad_type conditions.R
14 as_mapper cross cross.R
15 as_predicate_friendly_type_of cross cross.R
16 compact cross cross.R
17 is_bool cross cross.R
18 map_int vec_depth depth.R
19 as_predicate detect detect.R
20 index detect detect.R
21 as_predicate every every-some.R
22 detect_index head_while head-tail.R
23 negate head_while head-tail.R
24 as_mapper imap imap.R
25 vec_index imap imap.R
26 map2 imap imap.R
27 probe keep keep.R
28 list_recurse list_modify list-modify.R
29 lmap_at lmap lmap.R
30 as_mapper map map.R
31 as_mapper map2 map2-pmap.R
32 as_mapper modify.default modify.R
33 as_mapper negate negate.R
34 as_mapper safely output.R
35 capture_error safely output.R
36 signal_soft_deprecated partial partial.R
37 stop_defunct partial partial.R
38 map partial partial.R
39 paste_line partial partial.R
40 friendly_type_of partial partial.R
41 assign_in `pluck<-` pluck.R
42 as_mapper insistently rate.R
43 stop_bad_type insistently rate.R
44 capture_error insistently rate.R
45 rate_backoff insistently rate.R
46 is_rate insistently rate.R
47 rate_sleep insistently rate.R
48 rate_reset insistently rate.R
49 f insistently rate.R
50 reduce_impl reduce reduce.R
51 eval_dots rerun rerun.R
52 has_names rerun rerun.R
53 map2 invoke_map retired-invoke.R
54 as_invoke_function invoke_map retired-invoke.R
55 splice_if splice splice.R
56 check_tibble maybe_as_data_frame utils.R
graph <- igraph::graph_from_data_frame(x_rel_df,directed = TRUE)
igraph::V(graph)$parents <- names(igraph::V(graph))
ggraph(graph) +
geom_edge_link(
aes(colour = file),
arrow = grid::arrow(length = unit(0.05, "inches"))) +
geom_node_text(aes(label = parents),size = 3) +
labs(title = 'purrr function map', colour = 'Exported') +
ggplot2::theme(legend.position = 'bottom')
#> Using `nicely` as default layout
Subsetting Package Functions
sub_x <- subset(x,'compose')
Click the triangle to view the contents found in the subset containing
compose
and the functions the it calls.
details::details(lapply(sub_x,get_text),summary = 'Package subset')
Package subset
$compose.R
[1] "#' Compose multiple functions"
[2] "#'"
[3] "#' @param ... Functions to apply in order (from right to left by"
[4] "#' default). Formulas are converted to functions in the usual way."
[5] "#'"
[6] "#' These dots support [tidy dots][rlang::list2] features. In"
[7] "#' particular, if your functions are stored in a list, you can"
[8] "#' splice that in with `!!!`."
[9] "#' @param .dir If `\"backward\"` (the default), the functions are called"
[10] "#' in the reverse order, from right to left, as is conventional in"
[11] "#' mathematics. If `\"forward\"`, they are called from left to right."
[12] "#' @return A function"
[13] "#' @export"
[14] "#' @examples"
[15] "#' not_null <- compose(`!`, is.null)"
[16] "#' not_null(4)"
[17] "#' not_null(NULL)"
[18] "#'"
[19] "#' add1 <- function(x) x + 1"
[20] "#' compose(add1, add1)(8)"
[21] "#'"
[22] "#' # You can use the formula shortcut for functions:"
[23] "#' fn <- compose(~ paste(.x, \"foo\"), ~ paste(.x, \"bar\"))"
[24] "#' fn(\"input\")"
[25] "#'"
[26] "#' # Lists of functions can be spliced with !!!"
[27] "#' fns <- list("
[28] "#' function(x) paste(x, \"foo\"),"
[29] "#' ~ paste(.x, \"bar\")"
[30] "#' )"
[31] "#' fn <- compose(!!!fns)"
[32] "#' fn(\"input\")"
[33] "compose <- function(..., .dir = c(\"backward\", \"forward\")) {"
[34] " .dir <- arg_match(.dir, c(\"backward\", \"forward\"))"
[35] ""
[36] " fns <- map(list2(...), rlang::as_closure, env = caller_env())"
[37] " if (!length(fns)) {"
[38] " # Return the identity function"
[39] " return(compose(function(x, ...) x))"
[40] " }"
[41] ""
[42] " if (.dir == \"backward\") {"
[43] " n <- length(fns)"
[44] " first_fn <- fns[[n]]"
[45] " fns <- rev(fns[-n])"
[46] " } else {"
[47] " first_fn <- fns[[1]]"
[48] " fns <- fns[-1]"
[49] " }"
[50] ""
[51] " body <- expr({"
[52] " out <- !!fn_body(first_fn)"
[53] ""
[54] " fns <- !!fns"
[55] " for (fn in fns) {"
[56] " out <- fn(out)"
[57] " }"
[58] ""
[59] " out"
[60] " })"
[61] ""
[62] " structure("
[63] " new_function(formals(first_fn), body, fn_env(first_fn)),"
[64] " class = c(\"purrr_function_compose\", \"function\"),"
[65] " first_fn = first_fn,"
[66] " fns = fns"
[67] " )"
[68] "}"
$map.R
[1] "#' Apply a function to each element of a vector"
[2] "#'"
[3] "#' @description"
[4] "#'"
[5] "#' The map functions transform their input by applying a function to"
[6] "#' each element and returning a vector the same length as the input."
[7] "#'"
[8] "#' * `map()`, `map_if()` and `map_at()` always return a list. See the"
[9] "#' [modify()] family for versions that return an object of the same"
[10] "#' type as the input."
[11] "#'"
[12] "#' The `_if` and `_at` variants take a predicate function `.p` that"
[13] "#' determines which elements of `.x` are transformed with `.f`."
[14] "#'"
[15] "#' * `map_lgl()`, `map_int()`, `map_dbl()` and `map_chr()` each return"
[16] "#' an atomic vector of the indicated type (or die trying)."
[17] "#'"
[18] "#' The return value of `.f` must be of length one for each element of"
[19] "#' `.x`. If `.f` uses an extractor function shortcut, `.default`"
[20] "#' can be specified to handle values that are absent or empty. See"
[21] "#' [as_mapper()] for more on `.default`."
[22] "#'"
[23] "#' * `map_dfr()` and `map_dfc()` return data frames created by"
[24] "#' row-binding and column-binding respectively. They require dplyr"
[25] "#' to be installed."
[26] "#'"
[27] "#' * `walk()` calls `.f` for its side-effect and returns the input `.x`."
[28] "#'"
[29] "#' @inheritParams as_mapper"
[30] "#' @param .x A list or atomic vector."
[31] "#' @param .p A single predicate function, a formula describing such a"
[32] "#' predicate function, or a logical vector of the same length as `.x`."
[33] "#' Alternatively, if the elements of `.x` are themselves lists of"
[34] "#' objects, a string indicating the name of a logical element in the"
[35] "#' inner lists. Only those elements where `.p` evaluates to"
[36] "#' `TRUE` will be modified."
[37] "#' @param .at A character vector of names, positive numeric vector of"
[38] "#' positions to include, or a negative numeric vector of positions to"
[39] "#' exlude. Only those elements corresponding to `.at` will be modified."
[40] "#' @param ... Additional arguments passed on to the mapped function."
[41] "#' @return All functions return a vector the same length as `.x`."
[42] "#'"
[43] "#' `map()` returns a list, `map_lgl()` a logical vector, `map_int()` an"
[44] "#' integer vector, `map_dbl()` a double vector, and `map_chr()` a character"
[45] "#' vector. The output of `.f` will be automatically typed upwards,"
[46] "#' e.g. logical -> integer -> double -> character."
[47] "#'"
[48] "#' If `.x` has `names()`, the return value preserves those names."
[49] "#'"
[50] "#' `walk()` returns the input `.x` (invisibly). This makes it easy to"
[51] "#' use in pipe."
[52] "#' @export"
[53] "#' @family map variants"
[54] "#' @examples"
[55] "#' 1:10 %>%"
[56] "#' map(rnorm, n = 10) %>%"
[57] "#' map_dbl(mean)"
[58] "#'"
[59] "#' # Or use an anonymous function"
[60] "#' 1:10 %>%"
[61] "#' map(function(x) rnorm(10, x))"
[62] "#'"
[63] "#' # Or a formula"
[64] "#' 1:10 %>%"
[65] "#' map(~ rnorm(10, .x))"
[66] "#'"
[67] "#' # The names of the input are preserved in the output:"
[68] "#' list(foo = 1, bar = 2) %>% map(`+`, 10)"
[69] "#'"
[70] "#' # Using set_names() with character vectors is handy to keep track"
[71] "#' # of the original inputs:"
[72] "#' set_names(c(\"foo\", \"bar\")) %>% map_chr(paste0, \":suffix\")"
[73] "#'"
[74] "#' # Extract by name or position"
[75] "#' # .default specifies value for elements that are missing or NULL"
[76] "#' l1 <- list(list(a = 1L), list(a = NULL, b = 2L), list(b = 3L))"
[77] "#' l1 %>% map(\"a\", .default = \"???\")"
[78] "#' l1 %>% map_int(\"b\", .default = NA)"
[79] "#' l1 %>% map_int(2, .default = NA)"
[80] "#'"
[81] "#' # Supply multiple values to index deeply into a list"
[82] "#' l2 <- list("
[83] "#' list(num = 1:3, letters[1:3]),"
[84] "#' list(num = 101:103, letters[4:6]),"
[85] "#' list()"
[86] "#' )"
[87] "#' l2 %>% map(c(2, 2))"
[88] "#'"
[89] "#' # Use a list to build an extractor that mixes numeric indices and names,"
[90] "#' # and .default to provide a default value if the element does not exist"
[91] "#' l2 %>% map(list(\"num\", 3))"
[92] "#' l2 %>% map_int(list(\"num\", 3), .default = NA)"
[93] "#'"
[94] "#'"
[95] "#' # Use a predicate function to decide whether to map a function:"
[96] "#' map_if(iris, is.factor, as.character)"
[97] "#'"
[98] "#' # Specify an alternative with the `.else` argument:"
[99] "#' map_if(iris, is.factor, as.character, .else = as.integer)"
[100] "#'"
[101] "#' # A more realistic example: split a data frame into pieces, fit a"
[102] "#' # model to each piece, summarise and extract R^2"
[103] "#' mtcars %>%"
[104] "#' split(.$cyl) %>%"
[105] "#' map(~ lm(mpg ~ wt, data = .x)) %>%"
[106] "#' map(summary) %>%"
[107] "#' map_dbl(\"r.squared\")"
[108] "#'"
[109] "#' # Use map_lgl(), map_dbl(), etc to reduce to a vector."
[110] "#' # * list"
[111] "#' mtcars %>% map(sum)"
[112] "#' # * vector"
[113] "#' mtcars %>% map_dbl(sum)"
[114] "#'"
[115] "#' # If each element of the output is a data frame, use"
[116] "#' # map_dfr to row-bind them together:"
[117] "#' mtcars %>%"
[118] "#' split(.$cyl) %>%"
[119] "#' map(~ lm(mpg ~ wt, data = .x)) %>%"
[120] "#' map_dfr(~ as.data.frame(t(as.matrix(coef(.)))))"
[121] "#' # (if you also want to preserve the variable names see"
[122] "#' # the broom package)"
[123] "#'"
[124] "#' # Use `map_depth()` to recursively traverse nested vectors and map"
[125] "#' # a function at a certain depth:"
[126] "#' x <- list(a = list(foo = 1:2, bar = 3:4), b = list(baz = 5:6))"
[127] "#' str(x)"
[128] "#' map_depth(x, 2, paste, collapse = \"/\")"
[129] "#'"
[130] "#' # Equivalent to:"
[131] "#' map(x, map, paste, collapse = \"/\")"
[132] "map <- function(.x, .f, ...) {"
[133] " .f <- as_mapper(.f, ...)"
[134] " .Call(map_impl, environment(), \".x\", \".f\", \"list\")"
[135] "}"
$reduce.R
[1] " fn <- function(x, y, ...) .f(y, x, ...)"
Consolidating Subsetted Functions into a File
pack_path <- repack(sub_x)
#> Functions packed to /var/folders/kx/t4h_mm1910sb7vhm_gnfnx2c0000gn/T//Rtmpgg7cm0/foreman/unpacked.R
Click the triangle to view the contents found in the file containing the consolidated functions.
details::details(file.path(pack_path,'unpacked.R'),summary = 'Consolidated Script')
Consolidated Script
#Generated by foreman:
#' Compose multiple functions
#'
#' @param ... Functions to apply in order (from right to left by
#' default). Formulas are converted to functions in the usual way.
#'
#' These dots support [tidy dots][rlang::list2] features. In
#' particular, if your functions are stored in a list, you can
#' splice that in with `!!!`.
#' @param .dir If `"backward"` (the default), the functions are called
#' in the reverse order, from right to left, as is conventional in
#' mathematics. If `"forward"`, they are called from left to right.
#' @return A function
#' @export
#' @examples
#' not_null <- compose(`!`, is.null)
#' not_null(4)
#' not_null(NULL)
#'
#' add1 <- function(x) x + 1
#' compose(add1, add1)(8)
#'
#' # You can use the formula shortcut for functions:
#' fn <- compose(~ paste(.x, "foo"), ~ paste(.x, "bar"))
#' fn("input")
#'
#' # Lists of functions can be spliced with !!!
#' fns <- list(
#' function(x) paste(x, "foo"),
#' ~ paste(.x, "bar")
#' )
#' fn <- compose(!!!fns)
#' fn("input")
compose <- function(..., .dir = c("backward", "forward")) {
.dir <- arg_match(.dir, c("backward", "forward"))
fns <- map(list2(...), rlang::as_closure, env = caller_env())
if (!length(fns)) {
# Return the identity function
return(compose(function(x, ...) x))
}
if (.dir == "backward") {
n <- length(fns)
first_fn <- fns[[n]]
fns <- rev(fns[-n])
} else {
first_fn <- fns[[1]]
fns <- fns[-1]
}
body <- expr({
out <- !!fn_body(first_fn)
fns <- !!fns
for (fn in fns) {
out <- fn(out)
}
out
})
structure(
new_function(formals(first_fn), body, fn_env(first_fn)),
class = c("purrr_function_compose", "function"),
first_fn = first_fn,
fns = fns
)
}
#' Apply a function to each element of a vector
#'
#' @description
#'
#' The map functions transform their input by applying a function to
#' each element and returning a vector the same length as the input.
#'
#' * `map()`, `map_if()` and `map_at()` always return a list. See the
#' [modify()] family for versions that return an object of the same
#' type as the input.
#'
#' The `_if` and `_at` variants take a predicate function `.p` that
#' determines which elements of `.x` are transformed with `.f`.
#'
#' * `map_lgl()`, `map_int()`, `map_dbl()` and `map_chr()` each return
#' an atomic vector of the indicated type (or die trying).
#'
#' The return value of `.f` must be of length one for each element of
#' `.x`. If `.f` uses an extractor function shortcut, `.default`
#' can be specified to handle values that are absent or empty. See
#' [as_mapper()] for more on `.default`.
#'
#' * `map_dfr()` and `map_dfc()` return data frames created by
#' row-binding and column-binding respectively. They require dplyr
#' to be installed.
#'
#' * `walk()` calls `.f` for its side-effect and returns the input `.x`.
#'
#' @inheritParams as_mapper
#' @param .x A list or atomic vector.
#' @param .p A single predicate function, a formula describing such a
#' predicate function, or a logical vector of the same length as `.x`.
#' Alternatively, if the elements of `.x` are themselves lists of
#' objects, a string indicating the name of a logical element in the
#' inner lists. Only those elements where `.p` evaluates to
#' `TRUE` will be modified.
#' @param .at A character vector of names, positive numeric vector of
#' positions to include, or a negative numeric vector of positions to
#' exlude. Only those elements corresponding to `.at` will be modified.
#' @param ... Additional arguments passed on to the mapped function.
#' @return All functions return a vector the same length as `.x`.
#'
#' `map()` returns a list, `map_lgl()` a logical vector, `map_int()` an
#' integer vector, `map_dbl()` a double vector, and `map_chr()` a character
#' vector. The output of `.f` will be automatically typed upwards,
#' e.g. logical -> integer -> double -> character.
#'
#' If `.x` has `names()`, the return value preserves those names.
#'
#' `walk()` returns the input `.x` (invisibly). This makes it easy to
#' use in pipe.
#' @export
#' @family map variants
#' @examples
#' 1:10 %>%
#' map(rnorm, n = 10) %>%
#' map_dbl(mean)
#'
#' # Or use an anonymous function
#' 1:10 %>%
#' map(function(x) rnorm(10, x))
#'
#' # Or a formula
#' 1:10 %>%
#' map(~ rnorm(10, .x))
#'
#' # The names of the input are preserved in the output:
#' list(foo = 1, bar = 2) %>% map(`+`, 10)
#'
#' # Using set_names() with character vectors is handy to keep track
#' # of the original inputs:
#' set_names(c("foo", "bar")) %>% map_chr(paste0, ":suffix")
#'
#' # Extract by name or position
#' # .default specifies value for elements that are missing or NULL
#' l1 <- list(list(a = 1L), list(a = NULL, b = 2L), list(b = 3L))
#' l1 %>% map("a", .default = "???")
#' l1 %>% map_int("b", .default = NA)
#' l1 %>% map_int(2, .default = NA)
#'
#' # Supply multiple values to index deeply into a list
#' l2 <- list(
#' list(num = 1:3, letters[1:3]),
#' list(num = 101:103, letters[4:6]),
#' list()
#' )
#' l2 %>% map(c(2, 2))
#'
#' # Use a list to build an extractor that mixes numeric indices and names,
#' # and .default to provide a default value if the element does not exist
#' l2 %>% map(list("num", 3))
#' l2 %>% map_int(list("num", 3), .default = NA)
#'
#'
#' # Use a predicate function to decide whether to map a function:
#' map_if(iris, is.factor, as.character)
#'
#' # Specify an alternative with the `.else` argument:
#' map_if(iris, is.factor, as.character, .else = as.integer)
#'
#' # A more realistic example: split a data frame into pieces, fit a
#' # model to each piece, summarise and extract R^2
#' mtcars %>%
#' split(.$cyl) %>%
#' map(~ lm(mpg ~ wt, data = .x)) %>%
#' map(summary) %>%
#' map_dbl("r.squared")
#'
#' # Use map_lgl(), map_dbl(), etc to reduce to a vector.
#' # * list
#' mtcars %>% map(sum)
#' # * vector
#' mtcars %>% map_dbl(sum)
#'
#' # If each element of the output is a data frame, use
#' # map_dfr to row-bind them together:
#' mtcars %>%
#' split(.$cyl) %>%
#' map(~ lm(mpg ~ wt, data = .x)) %>%
#' map_dfr(~ as.data.frame(t(as.matrix(coef(.)))))
#' # (if you also want to preserve the variable names see
#' # the broom package)
#'
#' # Use `map_depth()` to recursively traverse nested vectors and map
#' # a function at a certain depth:
#' x <- list(a = list(foo = 1:2, bar = 3:4), b = list(baz = 5:6))
#' str(x)
#' map_depth(x, 2, paste, collapse = "/")
#'
#' # Equivalent to:
#' map(x, map, paste, collapse = "/")
map <- function(.x, .f, ...) {
.f <- as_mapper(.f, ...)
.Call(map_impl, environment(), ".x", ".f", "list")
}
fn <- function(x, y, ...) .f(y, x, ...)
This example will use the installed library future
.
Using foreman with an compiled libraries is also simple
library(future)
#>
#> Attaching package: 'future'
#> The following objects are masked from 'package:igraph':
#>
#> %->%, %<-%
unpacked_future <- unpack(ns = 'future')%>%
relationship()%>%
as.data.frame()
graph <- igraph::graph_from_data_frame(unpacked_future,directed = TRUE)
igraph::V(graph)$parents <- names(igraph::V(graph))
igraph::V(graph)$exported <- names(igraph::V(graph))%in%ls('package:future')
ggraph(graph) +
geom_edge_link(
arrow = grid::arrow(length = unit(0.05, "inches")),alpha = 0.05) +
geom_node_text(aes(colour = exported,label = parents),size = 2) +
labs(title = 'future function map', colour = 'Exported') +
ggplot2::theme(legend.position = 'bottom')
#> Using `nicely` as default layout
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.