Home > OS >  Why are functions only sometimes first class variables in R? Using them from built-in data structure
Why are functions only sometimes first class variables in R? Using them from built-in data structure

Time:11-05

I am trying to understand how first class functions work in R. I had understood that functions were first class in R, but was sorely disappointed when applying that understanding. When a function is saved to a list, whether that be as an ordinary list, a vector or a dictionary style list or vector, it is no longer callable, leading to the following error:

Error: attempt to apply non-function

e.g.

print_func <- function() {
  print('hi')
}
print_func()
[1] "hi"

my_list = list(print_func)
my_list[0]()
Error: attempt to apply non-function

my_vector = c(print_func)
my_vector[0]()
Error: attempt to apply non-function

my_map <- c("a" = print_func)
my_map["a"]()
Error: attempt to apply non-function

So why is this? Does R not actually treat functions as first class members in all cases, or is there another reason why this occurs?

I see that R vectors also do unexpected things (for me - perhaps not for experienced R users) to nested arrays:

nested_vector <- c("a" = c("b" = 1))
nested_vector["a"]
<NA> 
  NA
nested_vector["a.b"]
a.b 
  1

Here it makes sense to me that "a.b" might reference the sub-member of the key "b" under the key "a". But apparently that logic goes out the window when trying to call the upper level key "a".

CodePudding user response:

R is 1-based; so, you refer to the first element of a vector using index 1 (and not 0 like in python).

There are two approaches to accessing list elements:

  • accessing list elements while keeping a list (return a list containing the desired elements)
  • pulling an element out of a list

In the first case, the subsetting is done using a single pair of brackets ([]) and you will always get a list back. Note that this is different from python where you get a list only if you select more than one element (lst = [fun1, fun2]; lst[0] return fun1 and not a one-element list like R while lst[0:2] returns a list).

In the second approach, the subsetting is done using a double pair of brackets ([[]]). you basically pull an element completely out of a list; more like subsetting one element out of a list in python.

print_func <- function() {
  print('hi')
}
print_func()


my_list = list(print_func)

mode(my_list[1])      # return a list (not a function); so, it's not callable
[1] "list"
mode(my_list[[1]])    # return a function; so, it's callable
[1] "function"
my_list[1]()          # error
my_list[[1]]()        # works
[1] "hi"
# 
my_vector = c(print_func)
mode(my_vector)         # a list, so, not callable
[1] "list"
my_vector[1]()          # error because it returns a list and not a function
my_vector[[1]]()        # works
[1] "hi"

When subsetting with names, the same logic of single and double pair of brackets applies

my_map <- c("a" = print_func)
mode(my_map)            # list, so, not callable
[1] "list"
my_map["a"]()           # error
my_map[["a"]]()         # works
[1] "hi"

CodePudding user response:

Limey pointed out my 2 issues in the comments. I was using a 0-index and I was using single brackets. If I use a 1-index and double brackets it works, and functions are treated as first class variables.

My issue is resolved, and hopefully I won't make that same mistake again.

  • Related