Skip to content

How should tail call recursion be handled? #60

Open
@dgkf

Description

Inspired by recent advances in the R language, I went ahead and implemented a form of tail call recursion. However, it necessarily executes in a "non-standard" way, greedily evaluating arguments to recursive calls.

This means that expectations of R would apply to most calls, but might be unexpected for tail-recursive calls.

Typical Evaluation

f <- function(n, result) {
  if (n > 0) { 
    cat(n, "\n")
    f(n - 1, result)
  } else {
    result
  }
}

f(3, stop("Done"))
#> 3
#> 2
#> 1
#> Error: Done

Tail-Recursive Evaluation

f <- function(n, result) {
 if (n > 0) { 
   cat(n, "\n")
   f(n - 1, result)
 } else {
   result
 }
}

f(3, stop("Done"))
#> Error: Done

This is because result is necessarily greedily evaluated. Recursive calls will not work with promises dependent on the parent frame or non-standard evaluation. The "right" approach here is a bit unclear, so I'm going to wait to see how the R version feels with all of R's non-standard eval tricks to see if I can learn something from the design.

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions