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.