treat vctrs record rcrd as a list
A vctrs record type, while implemented as a list (of equal-lengths vectors) under the hood, is otherwise treated as "atomic" externally (loosely speaking).
My naive expectation had been that purrr::map() would treat it thus and loop over it's length, not over the list of its internal structure.
library(vctrs)
new_rational <- function(n = integer(), d = integer()) {
# assertions from vignette dropped
new_rcrd(list(n = n, d = d), class = "vctrs_rational")
}
format.vctrs_rational <- function(x, ...) {
n <- field(x, "n")
d <- field(x, "d")
out <- paste0(n, "/", d)
out[is.na(n) | is.na(d)] <- NA
out
}
x <- new_rational(c(1, 1, 1), c(2, 2, 2))
# vctrs API sugggests a record, externally viewed, is NOT a list
vctrs::vec_is_list(x)
#> [1] FALSE
length(x)
#> [1] 3
# base R, oddly, agrees
lapply(x, str)
#> vctrs_rt [1:1] 1/2
#> vctrs_rt [1:1] 1/2
#> vctrs_rt [1:1] 1/2
#> [[1]]
#> <vctrs_rational[1]>
#> [1] 1/2
#>
#> [[2]]
#> <vctrs_rational[1]>
#> [1] 1/2
#>
#> [[3]]
#> <vctrs_rational[1]>
#> [1] 1/2
# but purrr treats a vctrs record as a list of *fields*
purrr::map(x, str)
#> vctrs_rt [1:1] 1/2
#> vctrs_rt [1:1] 1/2
#> $n
#> <vctrs_rational[1]>
#> [1] 1/2
#>
#> $d
#> <vctrs_rational[1]>
#> [1] 1/2
Created on 2021-02-25 by the reprex package (v1.0.0)
My expectation had been that purrr::map() would not break the external appearance of records and that, had I needed to get into the fields, I would have had to do that myself:
map(x, function(i) {
paste0(vctrs::field(i, "n"), vctrs::field(i, "d"))
})
Ps.: I've read many of the issues and lengthy discussions on map() and vctrs, and I hope this isn't a duplicate.
I'm guessing https://github.com/r-lib/vctrs/issues/495 is the closest one, though that's about implementing vctrs::vec_map().