16.6 R의 Infix 연산자

이 절에서는 infix 연산자에 대해 알아 보겠습니다. 이러한 연산자가 R에서 실제로 어떻게 작동하는지, 그리고 infix 연산자를 직접 만드는 방법 등에 대하여 알아 보겠습니다. 또한 R 프로그래밍에서 사용할 수 있는 사전에 정의된 다양한 infix 연산자에는 어떤 것이 있는지 알아 보겠습니다.

R에서 사용하는 대부분의 연산자는 이항 연산자(두 개의 피연산자를 가짐)입니다. 따라서 이들은 피연산자와 피연산자 사이에 사용되는 infix 연산자라고 할 수 있습니다. 실제로 이러한 연산자는 백그라운드에서 함수를 호출합니다.

예를 들어 a + b 라는 수식은 실제로는 +(a, b)와 같이 인수 ab를 받아들여 ` + ` () 함수를 호출하는 것과 같습니다.

참고 : 백틱 (``) 기호를 주목하기 바랍니다. 함수 이름에서 +를 특수 기호로 인식하기 때문에 백틱으로 묶어 줘야 합니다.

다음은 백그라운드에서 호출되는 실제 함수와 함께 몇 가지 예제 수식입니다.

16.6.1 infix 연산자의 작동 예

5 + 3
## [1] 8
`+`(5,3)                           # 5 + 3의 +연산자를 함수로 표현한 것입니다
## [1] 8
5 - 3
## [1] 2
`-`(5,3)
## [1] 2
5 * 3 - 1
## [1] 14
`-`(`*`(5,3),1)
## [1] 14

앞의 예를 보면 이제 R에서 사용자 정의 infix 연산자를 만들 수도 있는 것입니다. 이러한 infix 연산사를 위한 함수의 이름은 %로 시작하고 끝나게 정의합니다.

다음은 숫자가 정확히 다른 숫자로 나누어 지는지를 확인하는 사용자 정의 infix 연산자를 정의하는 함수입니다.

16.6.2 사용자 정의 infix 연산자의 예

`%divisible%` <- function(x,y) {
                      if (x%%y ==0) return (TRUE)
                      else          return (FALSE)
}

This function can be used as infix operator a %divisible% b or as a function call `%divisible%(a, b)`. Both are the same.

이 함수는 infix 연산자a %divisible% b 또는 함수 호출`%divisible%(a, b)로 사용할 수 있습니다.

x <- c(4, 8, 6, 3)
y <- c(2, 3, 2, 2)
x %divisible% y
## Warning in if (x%%y == 0) return(TRUE) else return(FALSE): length > 1 이라는 조
## 건이 있고, 첫번째 요소만이 사용될 것입니다
## [1] TRUE
`%divisible%`(x, y)
## Warning in if (x%%y == 0) return(TRUE) else return(FALSE): length > 1 이라는 조
## 건이 있고, 첫번째 요소만이 사용될 것입니다
## [1] TRUE

참고로 2개의 벡터 x, y 를 인수로 받아 들여, 이 두 벡터의 요소 각각에 대한 %divisible% 연산자를 적용하는 함수를 생성해 보았습니다.

## 요소의 갯수가 적은 벡터를 자동 반복으로 채워주는 함수입니다.
vec.cycle <- function(x, j, k) {             # x : 짧은 벡터이며, 
                                             # j : 벡터 전체의 자동반복 횟수
                                             # k : 마지막으로 채워 넣어야 할 요소의 수입니다.
  vec <- x
  if (j>=2) {                                # 벡터 전체를 자동 반복으로 복사합니다.
    for (t1 in 1:(j-1)) vec <- c(vec, vec)
  }
  
  for (t2 in 1:k)                            # 남은 요소를 자동으로 채워 넣기 합니다.
    vec <- c(vec, vec[t2])
  
  return(vec)
}

## infix 연산자를 정의합니다.
`%divisible%` <- function(x, y, na.rm  = FALSE) {

#  if (na.rm == TRUE) {
#      x <- x[!is.na(x)]
#      y <- y[!is.na(y)]
#  }
    
  len.x <- length(x)         # x 벡터의 길이를 반환합니다.
  len.y <- length(y)         # y 벡터의 길이를 반환합니다.
  
  if (len.x >= len.y) {      # 벡터 x가 긴 경우입니다. 
    j <- len.x %/% len.y     # 벡터 전체를 반복할 횟수를 계산합니다.
    k <- len.x %% len.y      # 부족한 벡터 요소 갯수를 계산합니다.
    y <- vec.cycle(y, j, k)  # y를 자동반복으로 채워줍니다.
  }
  else {
    j <- len.y %/% len.x 
    k <- len.y %% len.x 
    x <- vec.cycle(x, j, k)
    
  }
  
#  result <- NULL
#  for (i in 1:length(x)) {    # 각 요소별로 %% 연산 결과를 저장합니다.
#      if (x[i] %% y[i] == 0)   result[i] <- TRUE
#      else                     result[i] <- FALSE
#  }
#  return(result)              # 최종 연산결과를 반환합니다.
    
   return(x %% y == 0)         # x의 요소 각각을 y의 요소 각각으로 나누어지는지 결과를 반환한다. 
}

# 데이터 벡터입니다.
x <- c(2, 3, 2)
y <- c(4, 8, 6, 2, 4, 3, 8, 7)

# 두 벡터 데이터를 확인합니다.
x %divisible% y
## [1] FALSE FALSE FALSE  TRUE FALSE FALSE FALSE FALSE

자신만의 infix 연산자를 정의할 때 기억해야 할 점은 연산자의 이름은 %로 시작하고 %로 끝나야 한다는 것입니다. 함수를 정의할 때 함수 이름을 백틱(``)으로 묶어서 % 를 이스케이프 시켜 주어야 합니다.

16.6.3 R에 미리 정의되어 있는 infix 연산자

기호 설 명
%% 나머지 연산자
%/% 몫 연산자
%*% 행렬 곱하기
%o% 아웃터 곱하기
%x% Kronecker 곱하기
%in% 대응 연산자