Я хотел бы проверить, являются ли приведенные ниже строки действительными математическими выражениями:
s1 = 'sin(x)'
s2 = 'sin(x*m)'
s3 = 'sin'
s4 = 'sin(xm)'
Под словом "действительный" я имею в виду выражение, представляющее собой комбинацию операторов
- (должен использоваться вместе с переменными или константами)
- переменные
x
и / или m
- константы.
По этому определению s1
и s2
действительны, в то время как s3
и s4
не действительны.
Чтобы определить, является ли строка допустимой, я написал функциюcheckFxn
, который сначала пытается преобразовать строку в вызов или одну из ее частей. В случае успеха он затем рекурсивно просматривает дерево вызовов и проверяет вышеуказанные условия. Если условия выполнены, то звонок возвращается как есть. Если нет, выдается ошибка.
checkFxn <- function(x) {
lang <- str2lang(x)
checkFxn2 <- function(y) {
if(is.name(y)) {
stopifnot(deparse(y) %in% c('x', 'm'))
} else if(is.call(y)) {
stopifnot(is.function(eval(y[[1]])) | is.primitive(eval(y[[1]])))
lapply(y[-1], checkFxn2)
} else {
stopifnot(is.logical(y) | is.numeric(y) | is.complex(y))
}
return(y)
}
checkFxn2(lang)
}
#Applying checkFxn to s1-4
lapply(list(s1,s2,s3,s4), function(x) {try(checkFxn(x), silent = T)})
[[1]]
sin(x)
[[2]]
sin(x * m)
[[3]]
[1] "Error in checkFxn2(lang) : deparse(y) %in% c(\"x\", \"m\") is not TRUE\n"
attr(,"class")
[1] "try-error"
attr(,"condition")
<simpleError in checkFxn2(lang): deparse(y) %in% c("x", "m") is not TRUE>
[[4]]
[1] "Error in FUN(X[[i]], ...) : deparse(y) %in% c(\"x\", \"m\") is not TRUE\n"
attr(,"class")
[1] "try-error"
attr(,"condition")
<simpleError in FUN(X[[i]], ...): deparse(y) %in% c("x", "m") is not TRUE>
Кажется, она работает, как и ожидалось, но я опасаюсь моего использования eval
и задавался вопросом, может ли кто-нибудь предложить альтернативу его использованию? Я знаю, что он следует обычным лексическим правилам, поэтому меня беспокоит оценка переменных в глобальной среде - есть ли способ ограничить его область? Я прочитал главу о нестандартной оценке , но я не могу понять это.
Кроме того, есть ли способ определить, является ли базовая функция или примитив математическим оператором? Я хотел бы использовать что-то более конкретное, чем is.function
и is.primitive
.