0

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

David
  • 300
  • 1
  • 14
  • 1
    One immediate comment: you should access list elements with `[[`, not `[`. And lists and vectors in R are 1-based, not 0-based. – Limey Nov 05 '22 at 07:46
  • @Limey Thanks, I should have tried the list/vector examples with an index of 1. Though I just tested them with the index of 1 and they get the exact same error. I am finding debugging in R to also be quite difficult compared to Python! EDIT: Scratch that, it works with double bracket syntax. – David Nov 05 '22 at 07:50

1 Answers1

1

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"