Perl to Raku 가이드 — 연산자

Perl to Raku 가이드 — 연산자 (Operators)

Perl의 perlop 문서에서 익숙하게 쓰던 연산자들이 Raku에서는 이름이 바뀌거나 의미가 조금 달라진 경우가 많아요. =>가 화살표가 아니라 페어를 만들고, ->가 파괴(dereference) 대신 다른 의미로 쓰이기도 하죠. 이 문서는 Perl 연산자를 Raku 상당식으로 옮기는 참고용 목록이에요.

출처: Raku 공식 문서 — Perl to Raku guide: operators

본문

아래는 Perl 연산자와 그 Raku 상당식을 (되도록) 빠짐없이 나열한 목록이에요. 필요할 때마다 차이점에 대한 메모를 덧붙였어요.

참고 (NOTE)

이 문서는 연산자를 상세히 설명하지 않아요. Perl의 perlop 문서에 있는 연산자에서 Raku 상당식으로 안내하는 데 집중해요. Raku 상당식의 전체 문서는 <Raku 문서 — Operators>를 보세요.

연산자 우선순위와 결합성 (Operator precedence and associativity)

Raku의 연산자 우선순위 표는 Perl과 꽤 달라서 여기서 상세히 다루지 않아요. 특정 연산자의 Raku 우선순위·결합성을 알아야 한다면 를 참고하세요.

항(項)과 리스트 연산자 (Terms and list operators)

Perl의 perlop 문서에서 단항·리스트 연산자로 분류한 것들은 대개 printchdir처럼 함수로도 생각할 수 있는 것들이에요. 그래서 이들에 대한 정보는 <함수 가이드>에서 찾을 수 있어요.

괄호는 여전히 그룹화에 쓰여요. 다만 주의점 하나: Raku에서는 리스트를 만드는 건 괄호가 아니라 쉼표(,)예요. 그래서:

my @foo = 1,2,3,4,5;   # 괄호 불필요
.say for 1,2,3,4,5;    # 이것도 괄호 불필요

my $scalar = (1);      # 리스트가 아님, 쉼표가 없으니
my $list   = (1,);     # 스칼라 컨테이너 안의 List

화살표 연산자 (The arrow operator)

  • Perl의 =>(fat comma)에 대해서는 <쉼표 연산자>를 보세요.
  • 파괴 연산자 ->는 점(dot)으로 대체됐는데, 이 점은 메서드 호출에도 쓰여요. 그래서 Perl의 $arrayref->[7]는 Raku에서 $arrayref.[7], $user->name$user.name이 돼요. 참고로 Raku에서 파괴 연산은 드물어요.
  • Raku는 ->를 붙이는 데 사용해요.

자동 증가·자동 감소 (Auto-increment and auto-decrement)

Perl과 동일하게 동작해요. 다만 한 가지 주의할 점은 ++succ 메서드를, --pred 메서드를 호출해서 동작한다는 거예요. 내장 숫자 타입에서는 특별한 일이 없겠지만, 커스텀 타입은 자신만의 succ/pred를 정의할 수 있어서 그 경우 ++/--가 실제로 뭘 하는지 주의해서 봐야 해요.

거듭제곱 (Exponentiation)

예상대로 동작해요. Perl perlop에서의 주의 사항, 즉 **가 단항 마이너스보다 더 강하게 결합한다는 점(-2**4(-2)**4가 아니라 -(2**4)로 평가)은 Raku에서도 동일해요.

기호 단항 연산자 (Symbolic unary operators)

  • Perl처럼 단항 !는 논리 부정, -는 산술 부정을 해요. ?^는 비트 논리 부정으로, 문서에 따르면 !와 동등해요. 이들은 인자를 각각 으로 강제 변환한다는 점이 관련 있을 수 있어요.
  • Raku에서 단항 ~는 문자열 컨텍스트 연산자예요. 비트 정수 부정은 접두 +^를 쓰세요. 2의 보수(two's complement)를 가정해요.
  • +는 Raku에서 인자를 Numeric 타입으로 강제 변환하는 실제 효과가 있어요.
  • 단항 \는 이제 없어요. 정말 기존 명명된 변수의 '참조'를 얻고 싶다면 아이템 컨텍스트를 쓰면 돼요. $aref = item(@array)처럼요. 더 익숙하게는 $를 붙여서 $aref = $@array로 쓸 수도 있어요. 주의: 진짜 참조를 얻는 게 아니라, 참조된 객체를 담은 스칼라 컨테이너를 얻는 거예요.
  • 명명된 서브루틴의 '참조'는 & 시길로 얻을 수 있어요. $sref = &foo. 익명 배열·해시·서브는 생성할 때 즉시 기반 객체를 반환해요. $sref = sub { }.

결합 연산자 (Binding operators)

=~!~는 각각 ~~!~~로 대체됐어요. Perl의 smartmatch에 문제가 있다고 생각했던 분들이라면 Raku에서 훨씬 잘 동작한다는 소식을 반가워하실 거예요. 타입이 강해져서 추측이 줄었기 때문이에요. Raku에서 smartmatch가 어떻게 동작하는지 더 자세한 설명은 <smartmatch 문서>를 참고하세요.

곱셈 연산자 (Multiplicative operators)

이항 *, /, %는 Perl처럼 각각 곱셈·나눗셈·나머지를 해요.

이항 x는 Raku에서 조금 다르고 짝을 이루는 연산자가 있어요. print '-' x 80;은 80개의 대시 문자열을 주지만, Perl의 @ones = (1) x 80;(80개의 "1" 리스트) 동작을 원한다면 @ones = 1 xx 80;을 쓰세요.

덧셈 연산자 (Additive operators)

이항 +-는 예상대로 각각 덧셈·뺄셈을 해요.

.이 메서드 호출 연산자이므로, Raku에서 이항 ~는 문자열 연결 연산자로 동작해요.

시프트 연산자 (Shift operators)

<<>>는 각각 +<+>로 대체됐어요.

명명된 단항 연산자 (Named unary operators)

앞서 언급했듯 이들은 <함수 가이드>에서 찾을 수 있어요.

관계 연산자 (Relational operators)

이 연산자들은 전부 Perl과 동일하게 동작해요.

동등 연산자 (Equality operators)

==!=는 모두 Perl과 동일하게 동작해요.

<=>cmp는 Raku에서 다른 동작을 해요.

  • <=>는 숫자 비교를 하지만, Perl의 -1, 0, 1 대신 Order::Less, Order::Same, Order::More를 반환해요.
  • Perl의 cmp 동작(정수가 아니라 객체를 반환한다는 차이만 빼고)을 얻으려면 leg 연산자를 쓰면 돼요.
  • cmp는 인자의 기존 타입에 따라 <=> 또는 leg를 수행해요.
  • ~~는 Perl처럼 smartmatch 연산자이면서, 앞서 언급했듯 Raku에서는 (그냥) 매치 연산자이기도 해요.

Smartmatch 연산자

Raku에서 smartmatch가 어떻게 동작하는지 더 자세한 설명은 <smartmatch 문서>를 참고하세요.

비트 AND (Bitwise And)

이항 &는 Raku에서 +&예요.

비트 OR와 배타 OR (Bitwise Or and Exclusive Or)

비트 OR는 Perl의 |에서 Raku의 +|로 바뀌었어요. 마찬가지로 비트 XOR ^+^인데, 이 연산자는 정수에 대해 동작해요.

C 스타일 논리 AND / C 스타일 논리 OR

변경 없음.

논리 Defined-Or

Raku에서 //로 남아 있어요. 첫 번째 정의된 피연산자를 반환하고, 없으면 마지막 피연산자를 반환해요. 그리고 orelse라는 낮은 우선순위 버전도 있어요.

범위 연산자 (Range operators)

리스트 컨텍스트에서 ..는 범위 연산자로 동작하며 바꿀 필요가 없어야 해요. 다만 유용할 수 있는 제외형 범위 연산자가 있어요:

  • infix ..^ — 끝점을 제외
  • infix ^.. — 시작점을 제외
  • infix ^..^ — 시작점과 끝점 둘 다 제외
  • prefix ^ — 0에서 시작하며 끝점을 제외

다음 예시는 위 모든 범위 연산자의 효과를 보여줘요 (괄호는 메서드 호출을 허용하기 위해서만 썼어요):

(1..^5).list;  # (1 2 3 4)
(1^..5).list;  # (2 3 4 5)
(1^..^5).list; # (2 3 4)
(^5).list;     # (0 1 2 3 4)

Perl에서 스칼라 컨텍스트의 ..... 연산자는 flip-flop 연산자로 동작해요. 잘 알려지지 않고 덜 쓰이긴 하지만요. Raku에서는 이 연산자들이 각각 로 대체됐어요.

조건 연산자 (Conditional operator)

조건 연산자 ? :?? !!로 대체됐어요:

$x = $ok  ? $yes  : $no;  # Perl
$x = $ok ?? $yes !! $no;  # Raku

할당 연산자 (Assignment operators)

완전히 문서화되진 않았지만, S03은 수학·논리 할당 연산자가 예상대로 동작한다고 시사해요. 눈에 띄는 변화 하나는 .= 는 왼쪽의 객체(타입 객체일 수도 있음)에 대해 변경 메서드(mutating method)를 호출한다는 점이에요. 그래서 이런 유용한 관용구를 쓸 수 있어요:

class LongClassName {
    has $.frobnicate;
}
my LongClassName $bar .= new( frobnicate => 42 ); # 클래스 이름을 반복할 필요 없음

이렇게 하면 $barLongClassName 객체만 담을 수 있다는 걸 보장하면서, 클래스 이름을 반복(그리고 어쩌면 오타를 낼)할 필요도 없어요.

.~의 변화에 따라 ~=는 문자열 연결 할당이에요. 비트 할당 연산자는 숫자·문자열 버전(&= 등 vs &.= 등)으로 나뉘지 않을 가능성이 커요. 그 기능이 Perl에서도 현재 실험적이기 때문이에요 — 다만 이것 역시 명시적으로 문서화되진 않았어요.

쉼표 연산자 (Comma operator)

쉼표 연산자는 대체로 예상대로 동작하지만, 기술적으로 를 만들거나 함수 호출에서 인자를 구분해요. 함수 호출을 메서드 호출로 바꾸는 : 변형도 있어요 — <이 페이지>를 보세요.

=> 연산자(fat arrow)는 Perl의 "fat comma"처럼 왼쪽에 따옴표 없는 (보통) 식별자를 허용하지만, Raku에서는 단순히 구분자로 기능하는 대신 객체를 만들어요. Perl 코드 한 줄을 Raku로 문자 그대로 번역하려고 한다면 예상대로 동작할 거예요. Raku를 읽는 법을 배우려면 를 보면 새 문법이 설명돼 있어요.

리스트 연산자 (오른쪽) (List operators (rightward))

명명된 단항 연산자와 마찬가지로, 이들은 <함수(Functions)> 아래에서 다뤄져요.

논리 NOT (Logical Not)

!의 낮은 우선순위 버전이에요. !처럼 인자를 로 강제 변환해요.

논리 AND / 논리 OR·배타 OR

&&의 낮은 우선순위 버전은 Perl에서와 같아요. or||의 낮은 우선순위 버전이고, xor^^의 낮은 우선순위 버전이에요. 추가로 //의 낮은 우선순위 버전인 orelse도 있어요.

따옴표 및 따옴표류 연산자 (Quote and quote-like operators)

따옴표 구성의 모든 자세한 내용은 을 보세요.

  • 완전히 리터럴인 문자열을 허용하는 따옴표 연산자: Q 또는 「…」. 후자는 키보드에서 찾기 어려울 수 있어요(키보드에 따라). Q 따옴표 문자열에서는 백슬래시 이스케이프가 적용되지 않아요. 예: Q{This is still a closing curly brace → \}는 "This is still a closing curly brace → "로 렌더링돼요.
  • q는 예상대로 백슬래시 이스케이프를 허용해요. 예: q{This is not a closing curly brace → \}, but this is → }는 "This is not a closing curly brace → }, but this is →"를 반환해요. Perl에서처럼 동작을 단일 따옴표로 할 수도 있어요.
  • qq는 변수 보간을 허용해요. 다만 기본적으로 스칼라 변수만 보간돼요. 다른 변수를 보간하려면 변수 뒤에 대괄호를 붙여야 해요(소위 ). 예: @a = <1 2 3>; say qq/@a[] [email protected]/;는 "1 2 3 [email protected]"이 돼요. 해시도 같은 방식으로 보간돼요: %a = 1 => 2, 3 => 4; say "%a{}";는 페어 사이를 공백으로, 각 페어 안의 키와 값을 탭으로 구분한 문자열을 줘요 (그게 의 표준 문자열화이고, 해시는 문자열화될 때 Pair 리스트처럼 동작하기 때문이에요). 중괄호를 사용해 Raku 코드를 문자열에 보간할 수도 있어요. 자세한 내용은 을 보세요.
  • qw는 Perl처럼 동작하고 «<...>»로 렌더링할 수도 있어요. 예: qw/a b c/«<a b c>»와 동등해요.
  • 보간하는 qw 버전도 있어요. 바로 qqw예요. my $a = 42; say qqw/$a b c/;는 "42 b c"를 줘요.
  • 셸 따옴표는 qx로 가능하지만, Perl과 달리 백틱이 셸 따옴표를 하지 않고, Perl 변수는 qx 문자열에서 보간되지 않아요. 셸 명령 문자열에서 Perl 변수를 보간해야 한다면 qqx를 쓰면 돼요.
  • qr 연산자는 Raku에서 사라졌어요.
  • tr///는 Perl과 비슷하게 동작해요. 주의점은 범위를 다르게 지정한다는 거예요. "a-z"라는 범위 대신 "a..z", 즉 Perl의 범위 연산자를 쓰는 거예요. tr///에는 더 잘 문서화된 메서드 버전인 .trans가 있어요. .trans는 페어 리스트를 써요: $x.trans(['a'..'c'] => ['A'..'C'], ['d'..'q'] => ['D'..'Q'], ['r'..'z'] => ['R'..'Z']);. .trans 사용법에 대한 훨씬 더 자세한 설명은 <여기>에서 찾을 수 있어요. y/// 상당식은 없어졌어요.
  • Heredoc은 Raku에서 다르게 지정해요. 따옴표 연산자와 함께 :to를 쓰는데, 예를 들어 q:to/END/;는 "END"로 끝나는 heredoc을 시작해요. 마찬가지로 따옴표 연산자에 따라 이스케이프·보간을 얻어요. 즉 Q면 리터럴, q면 백슬래시 이스케이프, qq면 보간이에요.

입출력 연산자 (I/O operators)

Raku의 입출력에 대한 자세한 내용은 에서 찾을 수 있어요.

«<...>»이 Raku의 quote-words 구성이므로, <>는 파일에서 줄을 읽는 데 쓰이지 않아요. 파일명으로 객체를 만들거나 열린 파일핸들을 사용한 뒤, 두 경우 모두 .lines를 호출하면 돼요. 즉 my @a = "filename".IO.lines; 또는 my $fh = open "filename", :r; my @a = $fh.lines; (후자에서는 읽기 전용으로 파일을 열기 위해 :r을 쓰고 있어요). 반복적으로 처리하려면 이렇게 for 루프를 쓰면 돼요:

for 'huge-csv'.IO.lines -> $line {
    # Do something with $line
}

여기서 ->의 사용에 주목하세요. 그건 Block 문법의 일부이고, Raku에서 if, for, while 등에 필요해요.

파일 전체를 스칼라로 슬러프(slurp)하려면 — 놀랍게도 — .slurp 메서드를 쓰면 돼요. 예:

my $x = "filename".IO.slurp;
# ... 또는 ...
my $fh = open "filename", :r;
my $x = $fh.slurp;

<특수 변수 가이드>에서 언급하듯, ARGV 매직 입력 파일핸들은 $*ARGFILES로, 커맨드라인 인자의 @ARGV 배열은 @*ARGS로 대체됐어요.

No-ops

1 while foo();는 Perl과 같은 방식으로 동작하지만 경고를 만들어요. Raku에서는 관용구를 Nil while foo();로 써요.

비트 문자열 연산자 (Bitwise string operators)

위에서 각각 문서화했지만 정리하면:

  • 비트 정수 부정은 접두 +^. 비트 불리언 부정은 ?^.
  • 비트 AND는 +&.
  • 비트 정수 OR는 +|. 비트 정수 XOR는 infix +^. 비트 불리언 OR는 ?|.
  • 왼쪽·오른쪽 시프트는 +<+>.

더 알아보기 (Learn more)