Functional programming: applicability of parameters (.x) and (.) in purrr::map

Asked

Viewed 202 times

4

I’m migrating to the package purrr, mainly in relation to the use of the function map. But I’m having a hard time understanding the concepts of functional programming in purrr.

I would like to learn how to apply the parameters (.x) and (.) inside map, instead of using the function(x) with the family apply.

More precisely,

  • in which contexts to use (.x) and (.)?

  • (.x) and (.) are definitive substitutes for function(x)?

  • how to use (.x) and (.) in other Packages and functions, such as dplyr::mutate?

To demonstrate my difficulty, I try to write the following function in a map with (.x) and (.), which I can only with function(x):

library(tidyverse)

map(1:10,function(x){
  names<-str_c('var',x)
  assign(names,runif(30,20,100),envir=.GlobalEnv)
})

I have tried several settings with map and (.x) and (.), but only error messages are generated.

1 answer

6


The functions of purrr have the following syntax:

map(vetor_ou_lista, funcao)

Then what he does is apply the funcao for each element of vetor_ou_lista.

funcao can be any R function or an anonymous function, as in your example.

Anonymous functions as formulas

However, the purrr provides an alternative syntax to create anonymous functions.

This syntax works as follows:

map(vetor_ou_lista, ~mean(.x + 2))

In that case, the formula ~mean(.x +2)) is equivalent to using such a function as an argument:

function(.x) {
  mean(.x + 2)
}

Note the ~ is important to indicate that you are using the alternative syntax. This has to do with the purrr.

The case of .

Already the . comes by in general we use the pipe operator (%>%). By default pipe passes the object that is left as the first argument of the function that is to its right, but we can change this behavior using the ., for example:

TRUE %>% mean(x = 1:10, na.rm = .)

In the above case we are passing the . (TRUE) for the argument na.rm of function mean.

Another interesting and unintuitive behavior is that if you use . within a nested call within the right function, it will still use the left object as the first argument on the right. For example:

1:10 %>% cor(y  = rev(.))
#> -1

Note that in this case he calculates the correlation of x with rev(x) which would not have occurred if we did:

1:10 %>% cor(y  = .)
Error in is.data.frame(x) : argument "x" is missing, with no default

Therefore, we can use this behavior also with purrr, since the map is a function of R like any other. This can then work:

mtcars %>% keep(names(.) %in% c("gear", "carb"))

See that here, I don’t use ~, since I am returning a vector of TRUE and FALSE’s.

Its function

In the case of your function, I think the ideal would be to do something like this:

1:10 %>% 
  str_c("var", .) %>% 
  map(~assign(.x, runif(30,20,100),envir=.GlobalEnv))

Other packages

Starting from version 0.8.0 of dplyr (which has not yet gone to CRAN, but is on Github) you can use this syntax in the functions mutate_*, summarise_*, etc..

In version 0.8 you can do this, for example:

mtcars %>% mutate_at(c("cyl", "gear"), ~.x + 1e6)

Up to the previous versions, the way the dplyr was a little different because it used the function funs:

mtcars %>% mutate_at(vars(cyl, gear), funs(. + 1e6))

Browser other questions tagged

You are not signed in. Login or sign up in order to post.