Dada uma expressão aritmétrica, por exemplo x + y*z
, quero convertê-la para add(x, multiply(y, z))
.
Encontrei uma função útil aqui :
> getAST <- function(ee) purrr::map_if(as.list(ee), is.call, getAST)
> getAST(quote(x + y*z))
[[1]]
`+`
[[2]]
x
[[3]]
[[3]][[1]]
`*`
[[3]][[2]]
y
[[3]][[3]]
z
Pode-se usar rapply(result, as.character, how = "list")
para obter caracteres em vez de símbolos.
Como obter add(x, multiply(y, z))
deste AST (o resultado)? Isso se torna mais complicado quando há alguns parênteses:
> getAST(quote((x + y) * z))
[[1]]
`*`
[[2]]
[[2]][[1]]
`(`
[[2]][[2]]
[[2]][[2]][[1]]
`+`
[[2]][[2]][[2]]
x
[[2]][[2]][[3]]
y
[[3]]
z
Não exijo a resposta, devo usar a getAST
função. É apenas um caminho possível a seguir.
É claro que no meu caso de uso real as expressões são mais longas.
Aqui está uma solução (eu acho) para o caso em que não há parênteses:
getAST <- function(ee) purrr::map_if(as.list(ee), is.call, getAST)
ast <- rapply(getAST(quote(x + y*z)), as.character, how = "list")
convertAST <- function(ast) {
op <- switch(
ast[[1]],
"+" = "add",
"-" = "subtract",
"*" = "multiply",
"/" = "divide"
)
left <- ast[[2]]
right <- ast[[3]]
if(is.character(left) && is.character(right)) {
return(sprintf("%s(%s, %s)", op, left, right))
}
if(is.character(left)) {
return(sprintf("%s(%s, %s)", op, left, convertAST(right)))
}
if(is.character(right)) {
return(sprintf("%s(%s, %s)", op, convertAST(left), right))
}
return(sprintf("%s(%s, %s)", op, convertAST(left), convertAST(right)))
}
convertAST(ast)
Podemos usar substituto assim:
Se você quiser um resultado de sequência de caracteres, então
Pode ser apenas porque eu não entendo
rapply
muito bem, mas sempre que tento usá-lo meu código fica mais complexo do que apenas escrever minha própria função recursiva.Neste caso coloquei a função recursiva em um wrapper fino que permite a entrada direta de expressões sem usar
quote
(se desejar)Isso permite a entrada direta de uma expressão:
Ou entrada indireta:
E lida com aninhamentos arbitrariamente profundos, deixando os parênteses intactos: