I am trying to write a function in R called functionTree that takes an R expression and prints its structure in a tree format. The function should display the elements of the expression with their types and indent them according to their depth in the tree. I have the following requirements:
The assignment operator (<-) should be displayed at depth 0, as function: special.
The left-hand side of the assignment should be displayed at depth 0.
The function call on the right-hand side should be displayed at depth 1, f should be displayed as function:closure.
The arguments of the function call should be displayed at depth 1, as atoms.
I have the following code, but it doesn’t produce the expected indentation and depth levels:
functionTree <- function(expr, eframe = globalenv(), maxDepth = 3, closureRecursive = FALSE, depth = 0) {
# Helper function to determine the type description
getTypeDescription <- function(expr) {
if (is.symbol(expr)) {
return("symbol")
} else if (is.call(expr)) {
funcName <- as.character(expr[[1]])
if (funcName %in% c("<-", "=")) {
return("function:special")
} else if (funcName == "function") {
return("function:closure")
} else {
return("function:closure")
}
} else if (is.atomic(expr) && length(expr) == 1) {
return("atom")
} else {
return("unknown")
}
}
# Function to print the current expression and its type
printExpression <- function(expr, depth) {
indent <- paste(rep(" ", depth * 2), collapse = "") # Create indentation based on depth
typeDescription <- getTypeDescription(expr)
exprDescription <- deparse(expr)
if (length(exprDescription) > 1) {
exprDescription <- exprDescription[1]
}
# Ensure there is no attempt to print zero-length variable name
if (nchar(exprDescription) == 0) {
exprDescription <- "<empty>"
}
cat(indent, depth, " (", typeDescription, ") -> ", exprDescription, "n", sep = "")
}
# Base case: Stop the recursion if the maximum depth is exceeded
if (depth > maxDepth) {
return(invisible())
}
# Print the current expression
printExpression(expr, depth)
# If the expression is a call, recursively analyze its arguments
if (is.call(expr)) {
funcName <- as.character(expr[[1]])
if (funcName %in% c("<-", "=")) {
# Handle special case for assignment
functionTree(expr[[1]], eframe, maxDepth, closureRecursive, depth) # Print the assignment operator
functionTree(expr[[2]], eframe, maxDepth, closureRecursive, depth) # Print the left-hand side
functionTree(expr[[3]], eframe, maxDepth, closureRecursive, depth + 1) # Print the right-hand side
} else {
functionTree(expr[[1]], eframe, maxDepth, closureRecursive, depth + 1)
lapply(expr[-1], function(sub_expr) functionTree(sub_expr, eframe, maxDepth, closureRecursive, depth + 1))
}
}
}
# Example usage of the functionTree function
f <- function(n = 0) { n ^ 2 }
a <- quote(x <- f(5))
# Call the functionTree function with the example expression
functionTree(a)
I tried adjusting the depth and indentation within the function, but I couldn’t achieve the desired output. Any help to correct the function to produce the expected output would be appreciated.
My output:
0 (function:special) -> x <- f(5)
0 (symbol) -> <-
0 (symbol) -> x
1 (function:closure) -> f(5)
2 (symbol) -> f
2 (atom) -> 5
[[1]]
NULL
Expected output:
0 (function:special) -> <-
0 (symbol) -> x
1 (function:closure) -> f
1 (atom) -> 5
Basak Kaplan is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.