Ранее я рассказывал, как определять функции, которые безопасно оценивают свои аргументы и возвращают значение отсутствия, если аргумент не находится в области действия функции. Канонический пример — это функция LOG, которая определяется только для положительных аргументов. Например, чтобы оценить функцию LOG на последовательности (возможно, неположительных) значений, можно использовать следующую инструкцию IF-THEN/ELSE:

data Log;
input x @@;
if x > 0 then 
   logX = log(x);
else 
   logX = .;
datalines;
-1 1 2 . 0 10  
;
 
proc print; 
run;

На форумах по SAS я часто вижу вопросы от тех, кто пытается использовать функцию IFN для реализации такой же логики. То есть вместо IF-THEN/ELSE они пытаются использовать следующую однострочную команду на шаге DATA:

logX = ifn(x>0, log(x), .);

Хотя логика на первый взгляд такая же, есть небольшое отличие. Все три аргумента функции IFN оцениваются ПЕРЕД вызовом функции, и затем результаты оценки передаются функции. Например, если x = -1, то на этапе DATA происходит следующее:

  1. Оценивается логическое выражениеx>0. Если x = -1, выражение оценивается в значение 0.
  2. Оценивается второй аргумент log(x). Это происходит независимо от результата оценки первого выражения. Если x= -1, то выражение log(x) недействительно, и SAS выдаст следующее сообщение
      NOTE:Недопустимый аргумент функции LOG
      NOTE:Не удалось выполнить указанные математические операции. В качестве результатов операций были установлены значения отсутствия.
  3. Вызывается функция IFN в виде logX = IFN(0, ., .), в результате чего logX присваивается значение отсутствия.

На шаге 2 SAS безусловно оценивает log(x) для каждого значения x, что приводит к ошибкам "нарушение области действия", когда значение x не является положительным. Это именно та ситуация, которой программист пытался избежать! Напротив, инструкция IF-THEN/ELSE оценивает log(x), только когда значение x положительно. Следовательно, при использовании инструкции IF-THEN/ELSE журнал SAS останется чистым.

Существует множество ситуаций, в которых удобна функция IFN (и функция IFC). Но для тестирования области действия всегда используйте инструкцию IF-THEN / ELSE.

Оригинал статьи на английском