Reversing the promise

I saw this interesting post Reversing the technical interview by Kyle Kingsbury. For fun, I wrote the equivalent code in R, which looks like the following.

cons <- function(h, t) function(cond) if (cond) h else t  

prn_list <- function(l) {
    cat("(")
    while (TRUE) {
        cat(l(TRUE))
        if (is.null(l(FALSE))) {
            cat(")\n")
            break
        }
        else {
            cat(", ")
            l <- l(FALSE)
        }
    }
}

reverse <- function(l) {
    r <- NULL
    while (TRUE) {
        if (is.null(l)) {
            return(r)
        }
        else {
            r <- cons(l(TRUE), r)
            l <- l(FALSE)
        }
    }
}

Looks fine when printing the constructed list.

l <- cons(1L, cons(2L, cons(3L, NULL)))
prn_list(l)
# (1, 2, 3)

However, when trying to print the reversed list, it will print (1, 1, 1, ... infinitely.

prn_list(reverse(l))
# (1, 1, 1, ...

Do you see what’s going wrong? I looked at my code for quite a while, then tried to redefine cons.

cons <- function(h, t) {
    force(h)
    force(t)
    function(cond) if (cond) h else t
}
prn_list(reverse(l))
# (3, 2, 1)

It worked!

To simplify the problem, consider the following code.

a <- 42
genf <- function(a) {
    function() a
}
f1 <- genf(a)
f2 <- genf(a)

f1()
# [1] 42

a <- 43

f1()
# [1] 42
f2()
# [1] 43

The f1() and f2() return different values since f1 has already captured the original value, while f2 still holds the promise of a.

R