Подтвердить что ты не робот

Как вы вычисляете циклическую сложность для R-функций?

Цикломатическая сложность определяет, сколько возможных ветвей можно взять через функцию. Существует ли существующая функция/инструмент для вычисления ее для функций R? Если нет, предложения будут оценены наилучшим образом для записи.

Дешевое начало в этом направлении - подсчитать все вхождения if, ifelse или switch внутри вашей функции. Чтобы получить реальный ответ, вам нужно понять, когда начинаются и заканчиваются ветки, что намного сложнее. Может быть, некоторые инструменты анализа R помогут нам начать?

4b9b3361

Ответ 1

Кроме того, я только что нашел новый пакет под названием cyclocomp (выпущен 2016). Проверьте это!

Ответ 2

Вы можете использовать codetools::walkCode для перехода к дереву кода. К сожалению, документация на кодеки довольно редкая. Здесь объяснение и образец, чтобы вы начали.

walkCode принимает выражение и ходок кода. Кодовый ходок - это список, который вы создаете, который должен содержать три функции обратного вызова: handler, call и leaf. (Вы можете использовать вспомогательную функцию makeCodeWalker для обеспечения разумных реализаций по умолчанию каждого из них.) walkCode просматривает дерево кода и делает вызовы в ходу кода по мере его прохождения.

call(e, w) вызывается, когда встречается составное выражение. e - выражение, а w - сам хост кода. Реализация по умолчанию просто рекурсирует в дочерние узлы выражения (for (ee in as.list(e)) if (!missing(ee)) walkCode(ee, w)).

leaf(e, w) вызывается, когда встречается лист node в дереве. Опять же, e - это выражение листа node, а w - ходок кода. Реализация по умолчанию - это просто print(e).

handler(v, w) вызывается для каждого составного выражения и может быть легко использован для альтернативного поведения для call для определенных типов выражений. v - это представление символьной строки родительского элемента составного выражения (немного сложно объяснить), но в основном <-, если оно является выражением присваивания, {, если оно является началом блока, if, если оно if-statement и т.д.). Если обработчик возвращает NULL, тогда call вызывается, как обычно; если вместо этого вы возвращаете функцию, то вызываемое вместо функции.

Здесь представлен чрезвычайно упрощенный пример, который учитывает вхождения функции if и ifelse функции. Надеюсь, это поможет вам хотя бы начать!

library(codetools)

countBranches <- function(func) {
  count <- 0
  walkCode(body(func), 
           makeCodeWalker(
             handler=function(v, w) {
               if (v == 'if' || v == 'ifelse')
                 count <<- count + 1
               NULL  # allow normal recursion
             },
             leaf=function(e, w) NULL))
  count
}