I just saw that you're the creator of the package, congrats on that! Looks like a lot of fun and a hard task.
How to read code depends on how it is written, how much you know about what you're seeing and of course the intention about why you're looking at it.
An example why the whole thing is really difficult
lapply <- function (X, FUN, ...) {
FUN <- match.fun(FUN)
if (!is.vector(X) || is.object(X))
X <- as.list(X)
.Internal(lapply(X, FUN))
}
This is just a small block of code, you can call it with lapply. My intension now is to see what lapply does. At first, I don't read "assign a function to lapply", maybe I do, but I don't recognize it. I skip the "{" because it's always there, no need to read it. and "FUN <- match.fun(FUN)" is read as one expression "match FUN". Then I read "check if it's not a vector or an object" || and | is so close it does not matter when reading. then again a block of "convert it to list and call C". But this is completely different to teaching someone a code block. Then I would start with "I assign a function to lapply with the arguments ..." etc...
If you compare two code blocks:
x <- 1
x <- add(x, 1)
x <- add(x, 1)
x <- add(x, 1)
x <- add(x, 1)
x <- add(x, 1)
x <- add(x, 1)
x <- add(x, 1)
x <- add(x, 1)
x <- add(x, 1)
x <- add(x, 1)
and
x <- 1
x <- x %>%
add(1) %>%
add(1) %>%
add(1) %>%
add(1) %>%
add(1) %>%
add(1) %>%
add(1) %>%
add(1) %>%
add(1) %>%
add(1)
I read the same thing, I read it as one expression. Now it gets really complicated for you because when "reading" the expression you can only go line by line, expression after expression. When reading line by line you are forced to assign x always, but that happens so fast in my brain, that I don't read it because the pattern is everywhere.
Really complicated stuff!