Raku로의 이주 빠른 참조
Raku로의 이주 빠른 참조 (Perl to Raku nutshell)
이 페이지는 Perl에서 Raku로 바뀐 문법과 의미론에 대한 빠른 경로를 제공하려고 만들어졌어요. Perl에서 동작했지만 Raku에서는 다르게 써야 하는 것은 전부 여기에 실어야 해요 (반대로 Raku의 새로운 기능과 관용구는 꼭 실을 필요는 없어요).
따라서 이 문서는 초보자 튜토리얼이나 Raku 홍보 개요가 아니에요. Perl 배경이 탄탄한 Raku 학습자와 Perl 코드를 Raku로 포팅하는 사람을 위한 기술 참조예요.
몇 가지 역사적 문서는 Raku를 원래 이름인 Perl 6으로, Perl을 구체적으로 Perl 5로 부를 수 있다는 점을 알아두세요.
라이브러리 (CPAN / raku.land)
레이쿠 모듈 저장소는 https://raku.land/이에요.
쓰던 모듈이 Raku로 포팅되지 않았고 이 문서에 대안도 없다면, Raku에서의 사용이 아직 다뤄지지 않았을 가능성이 커요.
Inline::Perl5 프로젝트를 쓰면 Raku 코드에서 Perl 인터프리터의 내장 인스턴스로 Perl 코드를 실행해 Perl 모듈을 직접 use할 수 있어요. 아주 간단해요:
# :from<Perl5> 는 Raku가 (설치돼 있다면) Inline::Perl5를 먼저 로드하게 하고,
# 그 다음 Perl의 Scalar::Util 모듈을 로드하게 해요
use Scalar::Util:from<Perl5> <looks_like_number>;
say looks_like_number "foo"; # OUTPUT: «0»
say looks_like_number "42"; # OUTPUT: «1»
CPAN Butterfly Plan의 일환으로 상당수의 Perl 모듈이 API를 최대한 유지한 채 Raku로 포팅됐어요. https://raku.land/?q=CPAN5에서 찾을 수 있어요.
많은 Perl 내장 함수(지금까지 약 100개)가 같은 의미론으로 Raku에 포팅됐어요. 예를 들어 Perl의 shift 함수가 문맥에 따라 기본으로 @_ 또는 @ARGV에서 매직하게 시프트하는 것 같은 것들이요. https://raku.land/zef:lizmat/P5built-ins와 그 의존성에서 찾을 수 있어요.
문법 (Syntax)
두 언어 사이에는 식별자가 어떻게 정의되는지부터 시작해 몇 가지 문법 차이가 있어요.
식별자 (Identifiers)
Raku는 식별자에 대시(-), 밑줄(_), 아포스트로피('), 영숫자를 허용해요:
sub test-doesn't-hang { ... }
my $ความสงบ = 42;
my \Δ = 72; say 72 - Δ;
메서드 호출 (-> 에서 .으로)
Raku 코드를 조금이라도 읽어봤다면 메서드 호출 문법이 화살표 대신 점을 쓴다는 걸 금방 알 수 있어요:
$person->name # Perl
$person.name # Raku
점 표기법은 입력하기 쉽고 업계 표준이기도 해요. (참고로 문자열 연결은 이제 ~ 연산자로 해요.)
이름이 런타임까지 알려지지 않은 메서드를 호출하려면:
$object->$methodname(@args); # Perl
$object."$methodname"(@args); # Raku
따옴표를 빼면 Raku는 $methodname이 단순 문자열 이름이 아니라 Method 객체를 담고 있길 기대해요. 그렇습니다, Raku에서 모든 것이 객체로 간주될 수 있어요.
공백 (Whitespace)
Perl은 strict와 warnings를 켜도 놀라울 만큼 유연한 공백 사용을 허용해요:
# 비관용적이지만 유효한 Perl
say"Hello ".ucfirst ($people
[$ i]
->
name)."!"if$greeted[$i]<1;
Raku도 프로그래머의 자유와 창의성을 지지하지만, 일관되고 결정적이며 확장 가능한 문법(단일 패스 파싱, 도움 되는 오류 메시지, 사용자 정의 연산자 통합)이라는 설계 목표에 문법적 유연성을 균형 맞췄어요. 그래서 Perl에서 공백이 선택적인 여러 곳이 Raku에서는 필수 또는 금지예요. 실생활 Perl 코드와 충돌할 몇 가지:
- 인자 목록의 여는 괄호 앞에 공백 금지.
substr ($s, 4, 1); # Perl (Raku에서는 이게 substr에 List 타입 단일 인자를 전달하려는 것으로 해석)substr($s, 4, 1); # Raku substr $s, 4, 1; # Raku — 괄호 없는 대안 스타일 - 키워드 바로 뒤에 공백 필수.
my($alpha, $beta); # Perl, Raku에서는 my() sub 호출을 시도my ($alpha, $beta); # Rakuif($a < 0) { ... } # Perl, Raku에서는 죽음if ($a < 0) { ... } # Raku if $a < 0 { ... } # Raku, 더 관용적 - 전치 연산자 뒤, 또는 후치/postcircumfix 연산자(배열/해시 첨자 포함) 앞에 공백 금지.
$seen {$_} ++; # Perl%seen{$_}++; # Raku - 기존 postfix/postcircumfix 연산자와 충돌한다면 중위 연산자 앞에 공백 필수.
$n<1; # Perl (Raku에서는 postcircumfix < > 와 충돌)$n < 1; # Raku - 메서드 호출의 점 앞에는 공백 허용!
Raku에서 공백이 허용되지 않는 곳에 공백을 넣으려면 unspace를 쓸 수 있어요.# Raku my @books = $xml .parse-file($file) # 어떤 주석 .findnodes("/library/book");
시길 (Sigils)
Perl에서는 배열과 해시가 접근 방식에 따라 시길을 바꿔요. Raku에서는 시길이 불변이라 변수를 어떻게 쓰든 같아요. 시길을 변수 이름의 일부라고 생각하면 돼요.
- $ (스칼라):
$시길은 이제 항상 "스칼라" 변수와 함께 쓰이고(배열 인덱싱, 해시 인덱싱에는 더 이상 안 써요).$x[1],$x{"foo"}를 쓸 수는 있지만$x에 대해 동작하며 같은 이름의@x/%x에는 영향이 없어요. 그런 건 이제@x[1],%x{"foo"}로 접근해요. - @ (배열):
@시길은 이제 항상 "배열" 변수와 함께 쓰이고, 더 이상 해시 value 슬라이싱에 안 써요. - % (해시):
%시길은 이제 항상 "해시" 변수와 함께 쓰이고, 더 이상 배열 key/value 슬라이싱에 안 써요. - & (Sub):
&시길은 이제 (백슬래시 없이) 일관되게 쓰여, 이름 붙은 서브루틴/연산자의 함수 객체를 호출하지 않고 가리킬 때, 즉 이름을 "동사"가 아닌 "명사"로 쓸 때 사용해요:my $sub = \&foo; # Perlmy $sub = &foo; # Raku
Raku에서는 어휘 스코프가 컴파일을 마치면 기호를 추가/제거할 수 없으므로 Perl의callback => &say # Raku — & 는 어떤 sub의 "명사" 형태를 줌undef &foo;에 해당하는 게 없고,defined &foo에 가장 가까운 것은defined ::('&foo')이에요. 단,my &foo;로 변경 가능한 명명된 서브루틴을 선언한 뒤 런타임에&foo에 할당해 그 의미를 바꿀 수 있어요. Perl에서&시길로 호출하는 특별한 형태들은 Raku에 없어요: - * (Glob): Perl에서
*시길은 Perl이 비어휘 변수·파일핸들·sub·포맷을 저장하는 GLOB 구조를 가리켰어요. 지원하지 않는 초기 Perl 코드에서 파일핸들을 sub에 넘겨야 할 때 만날 가능성이 높아요. Raku로 번역하기 전에 GLOB 필요성을 없애도록 Perl 코드를 리팩터링해야 해요.
배열 인덱싱/슬라이싱 []
배열 인덱스·슬라이스 연산은 더 이상 변수의 시길을 바꾸지 않고, 어드바로 슬라이스 종류를 제어할 수 있어요:
say @months[2]; # Raku — $ 대신 @
say join ',', @months[6, 8..11]; # Perl과 Raku 공통 (value 슬라이싱)
say join ',', @months[6, 8..11]:kv; # Raku — key/value 슬라이싱: :kv 어드바 사용
첨자 대괄호는 이제 특수 구문이 아니라 일반 postcircumfix 연산자라서, 요소 존재 확인과 요소 해제는 어드바로 해요. 배열의 가장 큰 인덱스는 .end 메서드로 구할 수 있어요.
say $#item; # Perl
say @item.end; # Raku
해시 인덱싱/슬라이싱 {}
해시 인덱스·슬라이스 연산도 시길을 바꾸지 않고, 어드바로 슬라이스 종류를 제어해요. 또한 단어 하나짜리 첨자는 중괄호 안에서 마법처럼 자동 인용되지 않고, 대신 항상 내용을 자동 인용하는 새 각괄호(angle brackets) 버전이 있어요(qw// 인용과 같은 규칙):
say %calories{"apple"}; # Raku — $ 대신 %
say %calories<apple>; # Raku — 각괄호 사용
say %calories«"$key"»; # Raku — 이중 각괄호는 Str 리스트로 보간
say join ',', %calories{'pear', 'plum'}; # Raku — value 슬라이싱, $ 대신 %
say join ',', %calories<pear plum>; # Raku (더 예쁜 버전)
say join ',', %calories<pear plum>:kv; # Raku — key/value 슬라이싱
참조 만들고 사용하기
Perl에서는 익명 배열·해시·sub의 참조가 생성 시 반환되고, 기존 명명 변수의 참조는 \ 연산자로 만들었어요. "참조/역참조" 비유는 Raku의 컨테이너 시스템에 깨끗하게 대응되지 않아서, 참조 연산자의 실제 문법보다 의도에 집중해야 해요.
Raku에서는 기본 (단일) 객체가 전달돼요(일종의 참조 전달이라 볼 수 있어요).
my @array = 4,8,15;
{ $_[0] = 66 }(@array); # @array를 $_에 별칭해 블록 실행
say @array; # OUTPUT: «[66 8 15]»
@array의 기본 Array 객체가 전달되고, 그 첫 값이 선언된 루틴 안에서 수정돼요.
Perl 5.20+의 후치 역참조와 같은 decont(컨테이너 해제)는 Raku에서 .list/.hash 메서드로 해요:
# Raku
my @a = $contains-an-array.list; # 또는 @($arrayref)
my %h = $contains-a-hash.hash; # 또는 %($hashref)
"Zen" 슬라이스도 같은 일을 해요:
# Raku
my @a = $contains-an-array[];
my %h = $contains-a-hash{};
연산자 (Operators)
전체 세부사항은 연산자 문서를 참고하세요.
변경 없음:
+숫자 덧셈,-숫자 뺄셈,*숫자 곱셈,/숫자 나눗셈,%숫자 모듈로,**숫자 거듭제곱,++숫자 증가,--숫자 감소! && || ^불리언, 높은 우선순위not and or xor불리언, 낮은 우선순위== != < > <= >=숫자 비교eq ne lt gt le ge문자열 비교
콤마 (리스트 구분자)
변하지 않았지만, 배열 변수를 리스트로 펼치려면(앞/뒤에 항목을 추가하려면) | 연산자를 써야 해요 (Slip 참고):
my @numbers = 100, 200, 300;
my @more_numbers = 500, 600, 700;
my @all_numbers = |@numbers, 400, |@more_numbers;
오른쪽에 괄호가 필요 없다는 점을 주목하세요. 리스트를 만드는 건 리스트 구분자지 괄호가 아니에요!
<=> cmp (삼방 비교)
Perl에서는 -1, 0, 1을 반환했어요. Raku에서는 Order::Less, Order::Same, Order::More를 반환해요.
cmp는 이제leg로 불리고, 비교에 문자열 문맥을 강제해요.<=>는 여전히 숫자 문맥을 강제해요.- Raku의
cmp는 인자의 기존 타입에 따라<=>또는leg를 해요.
~~ 스마트매치 연산자
연산자는 안 바뀌었지만, 정확히 무엇이 매치되는지의 규칙은 두 인자의 타입에 달려 있고, 그 규칙은 Perl과 Raku에서 전혀 같지 않아요.
& | ^ (문자열/숫자/불리언 비트 연산)
Perl에서는 & | ^가 인자의 내용에 따라 호출됐어요. 예를 들어 31 | 33은 "31" | "33"과 다른 결과를 반환해요. Raku에서는 그 한 글자 연산자들이 제거되고, 인자를 필요한 문맥으로 강제하는 두 글자 연산자로 교체됐어요.
# 중위 연산자 (양쪽에 인자 하나씩)
+& +| +^ And Or Xor: 숫자
~& ~| ~^ And Or Xor: 문자열
?& ?| ?^ And Or Xor: 불리언
# 전치 연산자 (연산자 뒤에 인자 하나)
+^ Not: 숫자
~^ Not: 문자열
?^ Not: 불리언 (! 연산자와 동일)
<< >> (숫자 시프트)
+<와 +>로 교체됐어요.
say 42 << 3; # Perl
say 42 +< 3; # Raku
=> (펫 콤마)
Perl에서 =>는 콤마처럼 동작하면서 왼쪽을 인용했어요. Raku에서 =>는 Pair 연산자로, 원칙적으로는 꽤 다르지만 많은 상황에서 똑같이 동작해요. 해시 초기화나 해시참조를 기대하는 sub에 인자를 넘길 때 쓰고 있었다면 그대로 써도 돼요.
# Perl과 Raku 모두 동작
my %hash = ( AAA => 1, BBB => 2 );
get_the_loot( 'diamonds', { quiet_level => 'very', quantity => 9 }); # 중괄호 주의
리스트 일부를 인용하지 않으려는 편의 지름길로 =>를 쓰거나, KEY, VALUE 평면 리스트를 기대하는 sub에 인자를 넘길 때 쓰고 있었다면 계속 쓰면 코드가 깨질 수 있어요. 가장 쉬운 해결책은 그 펫 화살표를 일반 콤마로 바꾸고 왼쪽에 수동으로 따옴표를 붙이는 거예요. 또는 해시 슬러핑 하도록 sub API를 바꿀 수 있어요. 장기적으로는 Pair를 기대하도록 API를 바꾸는 게 좋지만, 그러려면 모든 sub 호출을 한 번에 바꿔야 해요.
? : (삼항)
조건 연산자 ? :가 ?? !!로 교체됐어요:
my $result = $score > 60 ? 'Pass' : 'Fail'; # Perl
my $result = $score > 60 ?? 'Pass' !! 'Fail'; # Raku
. (숫자·문자열 연결)
물결표로 교체됐어요. 기억법: 바늘과 실로 두 문자열을 "꿰맨다(stitching)"고 생각하세요.
$food = 'grape' . 'fruit'; # Perl
$food = 'grape' ~ 'fruit'; # Raku
x (반복 연산자)
Perl에서 x는 스칼라/리스트 문맥에서 다르게 동작하는 반복 연산자예요. Raku는 두 가지 다른 반복 연산자로 나눴어요:
x— 문자열 반복 (모든 문맥에서)xx— 리스트 반복 (모든 문맥에서)
기억법: x는 짧고 xx는 길다, 그래서 리스트에는 xx를 쓴다.
# Raku
print '-' x 80; # 대시 한 줄 출력 (변경 없음)
@ones = 1 xx 80; # 80개의 1로 된 리스트 (괄호 불필요)
@ones = 5 xx @ones; # 모든 요소를 5로 설정 (괄호 불필요)
.. ... (범위 연산자 / 플립플롭)
Perl에서 ..는 문맥에 따라 완전히 다른 두 연산자 중 하나였어요. 리스트 문맥의 ..는 익숙한 범위 연산자예요(번역 불필요). 스칼라 문맥의 ..와 ...는 잘 알려지지 않은 플립플롭 연산자였고, ff와 fff로 교체됐어요.
문자열 보간
Perl에서 "${foo}s"는 변수 이름과 그 옆의 일반 텍스트를 구분했어요. Raku에서는 중괄호를 시길까지 포함하도록 확장해 "{$foo}s"라고 해요. 이는 사실 표현식 보간의 아주 간단한 경우예요.
복합 문 (Compound statements)
조건문
if / elsif / else / unless — 대부분 변하지 않았어요. 조건 주위 괄호는 이제 선택 사항이지만, 쓴다면 키워드 바로 뒤에 오면 안 돼요(함수 호출로 해석됨). 조건 표현식을 변수에 바인딩하는 것도 약간 달라요:
if (my $x = dostuff()) {...} # Perl
if dostuff() -> $x {...} # Raku
unless 조건문은 Raku에서 단일 블록만 허용해요. elsif나 else 절을 허용하지 않아요.
given-when — given-when 구조는 if-elsif-else 체인이나 C의 switch-case와 같아요. 기본 구조:
given $value { # $_를 할당
when "a match" { # if $_ ~~ "a match"
# do-something();
}
when "another match" { # elsif $_ ~~ "another match"
# do-something-else();
}
default { # else
# do-default-thing();
}
}
일반적으로 when 문에서 스칼라 값이 given이 설정한 $_와 매치돼요. 더 일반적으로 매치들은 사실 $_에 대한 스마트매치라 정규표현식 같은 더 복잡한 엔티티로 조회할 수 있어요.
루프
while / until — 대부분 변하지 않았어요. 괄호는 선택 사항이지만 키워드 바로 뒤에 오면 안 돼요. 조건을 변수에 바인딩하는 것도 달라요:
while (my $x = dostuff()) {...} # Perl
while dostuff() -> $x {...} # Raku
파일핸들에서 줄 단위로 읽는 방식이 바뀌었어요. Perl에서는 while 루프에서 다이아몬드 연산자로 했어요. Raku에서는 for 문이 lazy라서 .lines 메서드로 for 루프에서 줄 단위로 읽어요.
while (<IN_FH>) { } # Perl
for $IN_FH.lines { } # Raku
또한 Raku에서는 줄이 기본으로 chomp돼요.
do while/until — 구조는 여전히 있지만 do가 repeat로 이름 바뀌어 구조가 하는 일을 더 잘 나타내요:
# Raku
repeat {
...
} while $x < 10;
repeat {
...
} until $x >= 10;
Perl의 장식 없는 do 블록(do {...})은 Raku에서도 같은 동작을 해요.
for / foreach — 먼저 흔한 오해를 짚으면, for와 foreach 키워드는 C-스타일 3표현 형태와 리스트 반복자 형태를 구분하는 게 아니에요! 사실 두 키워드는 서로 교체 가능하고, Perl 컴파일러는 괄호 안의 세미콜론을 보고 어떤 루프를 파싱할지 결정해요.
C-스타일 3요소 형태는 이제 loop 키워드를 쓰고 그 외엔 변하지 않았어요. 괄호는 여전히 필수예요.
loop ( my $i = 1; $i <= 10; $i++ ) { ... } # Raku
리스트 반복자 형태는 Raku에서 for이고 foreach는 더 이상 키워드가 아니에요. for 루프 규칙:
- 괄호는 선택 사항.
- 반복 변수(있으면)는 리스트 앞에서 리스트 뒤 + 화살표 연산자 뒤로 이동.
- 반복 변수는 이제 항상 어휘적.
my는 필요도 허용도 안 됨. - 반복 변수는 현재 리스트 요소에 대한 읽기 전용 별칭 (Perl에서는 읽기/쓰기 별칭!). 읽기/쓰기가 필요하면 반복 변수 앞의
->를<->로 변경.
for @cars -> $car {...} # Raku; 읽기 전용
for @cars <-> $car {...} # Raku; 읽기/쓰기
Raku에서는 주제 $_도 topic 변수로 쓰일 때 읽기 전용이 돼요 (<-> $_로 읽기/쓰기 가능). 화살표 뒤에 변수를 여러 개 지정하면 각 반복에서 리스트의 요소를 여러 개 소비할 수 있어요.
for @array -> $first, $second {
say "First is $first, second is $second";
}
요소 수가 화살표 뒤 변수 수의 배수가 아닌 경우 기본값을 가진 변수를 제공할 수 있어요.
for @array -> $first, $second = 0 {
say "First is $first, second is $second";
}
each — Perl의 while...each(%hash) / while...each(@array) (키/인덱스와 값 양쪽을 반복)에 해당하는 Raku 코드:
for @array.kv -> $i, $v { ... } # Raku
for %hash.kv -> $k, $v { ... } # Raku
흐름 제어 문
변경 없음: next, last, redo.
continue — 더 이상 continue 블록이 없어요. 대신 루프 본문 안에 NEXT 블록(phaser)을 쓰세요.
# Raku
my $str = '';
for 1..5 {
next if $_ % 2 == 1;
$str ~= $_;
NEXT {
$str ~= ':'
}
}
phaser는 사실 블록을 필요로 하지 않아요. 다른 스코프를 원하지 않을 때 아주 유용해요:
# Raku
NEXT $str ~= ':';
함수 (Functions)
네이키드 블록을 가진 내장 함수
이전에 네이키드 블록 뒤에 콤마 없이 나머지 인자를 받던 내장 함수(map, grep 등)는 이제 블록과 인자 사이에 콤마를 요구해요.
my @results = grep { $_ eq "bars" }, @foo; # Raku
delete
my $deleted_value = %hash{$key}:delete; # Raku — :delete 어드바 사용
my $deleted_value = @array[$i]:delete; # Raku — :delete 어드바 사용
exists
delete와 마찬가지로 어드바가 됐어요.
say "element exists" if %hash{$key}:exists; # Raku — :exists 어드바 사용
say "element exists" if @array[$i]:exists; # Raku — :exists 어드바 사용
정규표현식 (Regular expressions)
=~ 와 !~ 을 ~~ 와 !~~ 으로
Perl에서는 매치·치환을 =~ 정규식 바인딩 연산자로 변수에 대해 수행했어요. Raku에서는 ~~ 스마트매치 연산자를 써요.
next if $line ~~ /static/ ; # Raku
next if $line !~~ /dynamic/ ; # Raku
$line ~~ s/abc/123/; # Raku
대안으로 새 .match/.subst 메서드를 쓸 수 있어요. .subst는 비변형이에요.
캡처는 1이 아니라 0부터
/(.+)/ and print $0; # Raku — 캡처는 $0부터
수식어 이동
정규식 끝의 수식어를 앞으로 옮겨요. 평범한 매치(/abc/)에 선택적 m을 추가해야 할 수도 있어요.
next if $line ~~ m:i/static/ ; # Raku — 수식어 i를 앞으로
:P5 또는 :Perl5 어드바 추가
정규식이 복잡하면 P5 수식어를 추가해 (몇몇 예외를 제외하고) 그대로 쓸 수 있어요.
next if $line ~~ m:P5/[aeiou]/ ; # Raku, P5 수식어 사용
next if $line ~~ m/ <[aeiou]> / ; # Raku, 네이티브 새 문법
Perl 정규식에 수식어가 있으면 끝에서 옮겨 P5 수식어 뒤에 두세요. 각 수식어는 다른 것과 콜론으로 구분돼요.
my $a = "abcabc";
my $b = $a;
$a =~ s/abcaBc//gi; # Perl 5
$a ~~ s:P5:g:i/ab//; # Raku, P5 수식어 사용
$b ~~ s:gi/ab//; # Raku, 네이티브 새 문법
P5 문법에서 또 필요한 조정은, 표현식에서 Unicode를 지정할 때 중괄호를 대괄호로 바꾸는 거예요:
next if $line =~ m/\x{2043};
next if $line ~~ m:P5/\x[2043]/;
next if $line ~~ /\x[2043]/;
P5 문법에서 Raku에 구현되지 않은 두 기능이 Perl Unicode 속성 매처 \p{}와 \P{}예요.
특수 매처는 일반적으로 <> 문법 아래로
Perl 정규식이 지원하는 특수 매치 문법의 많은 경우, () 대신 <>로 둘러싸여요. 문자 클래스의 경우:
[abc]→<[abc]>[^abc]→<-[abc]>[a-zA-Z]→<[a..zA..Z]>[[:upper:]]→<:Upper>[abc[:upper:]]→<[abc]+:Upper>
lookaround 어서션의 경우:
(?=[abc])→<?[abc]>(?=ar?bitrary* pattern)→<before ar?bitrary* pattern>(?!=[abc])→<![abc]>(?!=ar?bitrary* pattern)→<!before ar?bitrary* pattern>(?<=pattern)→<after pattern>(?<!pattern)→<!after pattern>
LTM(최장 토큰 매치)이 대안(alternation)을 대체
Raku 정규식에서 |는 LTM을 수행하는데, 쓰인 순서가 아니라 규칙 집합에 기반해 모호한 매치에서 어떤 대안이 이길지 결정해요. 가장 간단한 해법은 Perl 정규식의 |를 ||로 바꾸는 거예요. 다만 매칭이 복잡해지면 둘 다, 특히 LTM 전략을 이해해야 해요.
이름 붙은 캡처
Perl의 (?<iswhat>\w+) + %+{iswhat}는 Raku에서 정규식 안에서 실제 할당으로 바뀌어요:
"þor is mighty" ~~ /is \s+ $<iswhat>=(\w+)/;
say $<iswhat>;
정규식 안에서 실제 할당이 이루어져요. 바깥의 변수에 쓰던 것과 같은 문법이에요.
주석
Perl과 마찬가지로 정규식에서 주석은 평소처럼 동작해요.
/ word #`(match lexical "word") /
BEGIN, UNITCHECK, CHECK, INIT, END
UNITCHECK를 제외한 이 특수 블록들은 Raku에 모두 존재해요. Raku에서는 이것들을 Phasers라고 불러요. 하지만 차이가 있어요!
UNITCHECK가 CHECK가 됨
Raku에는 현재 CHECK 블록의 직접적인 대응물이 없어요. Raku의 CHECK phaser는 Perl의 UNITCHECK 블록과 같은 의미론을 가져요: 발생한 컴파일 단위의 파싱이 끝날 때마다 실행돼요. 이는 Perl에서 CHECK 블록의 현재 의미론보다 훨씬 합리적인 의미론으로 간주돼요.
블록 불필요
Perl에서 이 특수 블록은 반드시 중괄호를 가져야 하므로 별도 스코프를 뜻해요. Raku에서는 그럴 필요가 없어서 주변 어휘 스코프와 스코프를 공유할 수 있어요.
BEGIN my $foo = 42; # Raku
사전 컴파일 관련 의미 변경
사전 컴파일되는 모듈에 BEGIN/CHECK phaser를 넣으면, 그 phaser는 사전 컴파일 중에만 실행되고 사전 컴파일된 모듈 로드 시에는 실행되지 않아요. 그래서 모듈 로드 시 실행되게 하려면 BEGIN/CHECK 블록을 INIT 블록으로 바꿔야 할 수 있어요.
프래그마 (Pragmas)
- strict: strict 모드는 이제 기본으로 켜져 있어요.
- warnings: warnings도 기본으로 켜져 있어요.
no warnings는 코드를quietly {}블록으로 감싸면 돼요. - autodie: 오류 시 예외를 던지도록 바뀌던 함수들이 이제 기본으로 Failure를 반환해요. Failure는 정의성/진실성을 문제없이 검사할 수 있고, 다른 방식으로 쓰면 감싸진 Exception이 던져져요.
# Raku my $i_fh = open $input_path, :r; # 오류 시 Failure 반환 if open($input_path,:r) -> $handle { .say for $handle.lines; } else { # open() 실패를 우아하게 처리 } - base, parent:
use base/use parent는 Raku에서 클래스 선언의is키워드로 교체됐어요.# Raku class Cat is Animal {}Animal클래스는 상속받기 전에 컴파일 시점에 알려져 있어야 해요. - bigint, bignum, bigrat: 더 이상 관련 없음. Int는 이제 임의 정밀도이고, Rat의 분자도 마찬가지예요(분모는
2**64로 제한되고, 넘으면 성능 유지를 위해 Num으로 자동 승격). 임의 정밀도 분모의 Rat을 원하면 FatRat이 있어요. - constant: Raku에서
constant는 변수용 선언자로,my와 같지만 변수가 초기화 표현식(컴파일 시점 평가)의 결과에 영구히 잠겨요.=>를=로 바꾸세요.constant DEBUG = 0; # Raku tau, pi, e, i; # Raku의 내장 상수 (τ, π, 𝑒 는 유니코드 표기) - encoding: Raku는 현재 스크립트에 utf8만 써요.
- use integer: Raku에는 그런 게 없어요. 계산에 네이티브 정수를 쓰면 가장 가까운 게 돼요.
my int $foo = 42; - use lib: 컴파일 시점에 모듈을 찾는 위치를 조작. [이런 경우엔
use lib문법은 같음]. - use mro: 더 이상 관련 없음. Raku에서 메서드 호출은 항상 C3 메서드 해석 순서를 써요. 부모 클래스를 찾으려면
.^mro메타메서드 호출:say Animal.^mro; # .^ 는 객체에 메타메서드 호출을 나타냄 - use utf8: 더 이상 관련 없음 — Raku에서 소스 코드는 utf8 인코딩일 것으로 기대돼요.
- use vars: Perl에서도 권장되지 않음. Raku로 번역 전에
use vars필요성을 없애도록 리팩터링해야 해요.
명령줄 플래그 (Command-line flags)
변경 없음: -c -e -h -I -n -p -v -V
- -a, -F: 코드를
.split을 수동으로 쓰도록 바꾸세요. - -l: 이제 기본 동작.
- -M -m:
-M만 남아요. - -E: 모든 기능이 이미 활성화돼 있으니 그냥 소문자
-e를 쓰세요. - -d, -dt, -d:foo, -D 등:
++BUG메타구문 옵션으로 교체됨. - -s: 스위치 파싱은 이제
MAIN서브루틴의 매개변수 목록으로 함.# Raku sub MAIN( Int :$xyz ) { say $xyz if $xyz.defined; }raku example.raku --xyz=5 5 - -t, -P, -u, -U, -W, -X: 제거됨.
- -w: 이제 기본 동작.
- -S, -T: 제거됨.
파일 관련 연산 (File-related operations)
텍스트 파일의 줄을 배열로 읽기
Perl의 관용구는 파일을 열고 <$fh>로 읽는 거였어요. Raku에서는:
my @lines = "file".IO.lines; # 자동 chomp
파일을 slurp한 다음 줄바꿈으로 split하는 유혹에 빠지지 마세요. 그렇게 하면 끝에 빈 요소가 하나 더 있는 배열이 나와요. 실제로 slurp하고 싶다면 slurp 결과에 lines 메서드를 호출하면 돼요.
또한 $!는 Raku에서 파일 IO 실패에 실제로 관련이 없어요. 실패한 IO 연산은 예외 대신 Failure를 반환해요. Perl과 비슷한 IO 오류 검사·보고:
my $fh = open('./bad/path/to/file', :w) or die $fh; # $! 대신 $fh
my $fh = open('./bad/path/to/file', :w) orelse .die; # Raku
Failure를 쓰려는 모든 연산은 프로그램에 결함을 일으키고 종료돼요. .self 메서드 호출만으로도 충분해요.
실행 파일의 표준 출력 캡처
Perl에서는 백틱이나 qx//를 썼어요. Raku에서는 셸을 안 쓰고 실행하는 걸 권장해요:
my $arg = 'Hello';
my $captured = run('echo', $arg, :out).out.slurp;
my $captured = run(«echo "$arg"», :out).out.slurp;
정말 셸을 쓰고 싶으면:
my $captured = shell("echo $arg", :out).out.slurp;
my $captured = qqx{echo $arg};
주의: 이 경우 보호가 전혀 없어요! run은 셸을 쓰지 않아 인자를 이스케이프할 필요가 없어요(직접 전달). shell이나 qqx를 쓰면 모든 것이 하나의 긴 문자열이 되어 셸로 전달돼요. 인자를 매우 신중히 검증하지 않으면 셸 주입 취약점이 생기기 쉬워요.
환경 변수 (Environment variables)
Perl은 모듈 검색 경로에 PERLLIB/PERL5LIB를 썼지만 Raku는 둘 다 무시해요. 대신 RAKULIB를 쓰고, 디렉터리 구분자도 :에서 ,로 바뀌었어요.
$ export RAKULIB=/module/dir1,/module/dir2;
RAKULIB를 지정하지 않으면 프로그램 안에서 use lib 프래그마로 라이브러리 경로를 지정해요. RAKULIB는 개발자 편의용이며(모듈 로딩이 OS 경로와 직접 호환되지 않으므로) 미래에 제거될 수 있으니 모듈 소비자는 쓰지 말아야 해요.
기타 (Misc.)
'0'은 True
Perl과 달리 '0'(0만으로 이루어진 문자열)은 True예요. Raku는 코어에 타입이 있어서 그게 더 합리적이에요. 그래서 Perl의 공통 패턴:
... if defined $x and length $x; # 또는 현대 perl의 그냥 length()
Raku에서는 단순히
... if $x;
가 돼요.
dump
사라졌어요. Raku 설계는 컴파일된 바이트코드의 자동·투명한 저장/로딩을 허용하지만 Rakudo는 지금까지만 모듈에 대해서만 지원해요.
AUTOLOAD
FALLBACK 메서드가 비슷한 기능을 제공해요.
모듈에서 특정 함수 가져오기
Perl에서는 use ModuleName qw{foo bar baz};로 선택적으로 가져왔어요. Raku에서는 관련 sub에 is export 역할을 지정해 내보낼 함수를 지정하고, 그 역할을 가진 모든 sub가 내보내져요:
unit module Bar;
sub foo($a) is export { say "foo $a" }
sub bar($b) is export { say "bar $b" }
sub baz($z) { say "baz $z" }
use Bar 하면 foo와 bar는 사용 가능하고, baz를 쓰려 하면 컴파일 시점에 "Undeclared routine" 오류가 나요.
Perl처럼 선택적으로 가져오려면, 내보낼 함수를 지정하는 EXPORT sub를 모듈 안에 정의하고 module Bar 문을 제거하면 돼요. 이제 그 모듈은 Bar.rakumod 파일이고 내용은:
sub EXPORT(*@import-list) {
my %exportable-subs =
'&foo' => &foo,
'&bar' => &bar,
;
my %subs-to-export;
for @import-list -> $import {
if grep $sub-name, %exportable-subs.keys {
%subs-to-export{$sub-name} = %exportable-subs{$sub-name};
}
}
return %subs-to-export;
}
sub foo($a, $b, $c) { say "foo, $a, $b, $c" }
sub bar($a) { say "bar, $a" }
sub baz($z) { say "baz, $z" }
그래서 호출 코드에서 use Bar <foo>; 하면 foo만 가져오고, bar는 내보내기 가능해도 명시적으로 가져오지 않으면 사용 불가능해요.
모듈에서 함수 그룹 가져오기
함수 그룹을 내보내려면 그룹에 이름을 붙이면 자동으로 동작해요. is export를 지정하면 :DEFAULT 그룹에 추가되지만, 다른 그룹이나 여러 그룹에 추가할 수도 있어요:
unit module Bar;
sub foo() is export { } # 기본으로 :DEFAULT에 추가
sub bar() is export(:FNORBL) { } # FNORBL 그룹에 추가
sub baz() is export(:DEFAULT:FNORBL) { } # 두 그룹 모두에 추가
use Bar; # foo / baz 가져옴
use Bar :FNORBL; # bar / baz 가져옴
use Bar :ALL; # foo / bar / baz 가져옴
:ALL은 is export 특성이 있는 모든 서브루틴을 포괄하는 자동 생성 그룹이에요.
코어 모듈 (Core modules)
Data::Dumper
Perl에서 직렬화와 디버깅 뷰에 쓰던 Data::Dumper의 역할은 Raku에서 모든 객체가 가진 .raku 메서드로 해결돼요.
# Raku
say @array_of_hashes.raku; # 배열에 .raku, 그 참조가 아니라
이름을 붙여주는 더 복잡한 선택적 호출 규약은, Raku에서는 변수의 시길 앞에 콜론을 두면 키가 변수명, 값이 변수값인 Pair로 바뀌는 걸로 대체돼요.
# Raku
say [ :$foo, :$bar, :@baz ].raku;
# OUTPUT: «["foo" => 42, "bar" => 44, "baz" => [16, 32, 64, "Hike!"]]»
Rakudo 전용 디버깅 도우미 dd(Tiny Data Dumper)도 있어요. 주어진 변수의 .raku 표현 + 추가 정보를 STDERR로 출력해요:
dd $foo, $bar, @baz;
# OUTPUT: «Int $foo = 42Int $bar = 44Array @baz = [16, 32, 64, "Hike!"]»
Getopt::Long
스위치 파싱은 이제 MAIN 서브루틴의 매개변수 목록으로 해요.
# Raku
sub MAIN( Int :$length = 24, :file($data) = 'file.dat', Bool :$verbose ) {
say $length if $length.defined;
say $data if $data.defined;
say 'Verbosity ', ($verbose ?? 'on' !! 'off');
}
Raku는 명령줄 파싱 오류 시 전체 사용 메시지를 자동 생성한다는 점을 주목하세요.
자동 번역 (Automated translation)
Perl 구문의 Raku 버전을 빠르게 찾는 방법은 자동 번역기를 돌리는 거예요. (이 번역기들은 아직 완성되지 않았어요.)
- Blue Tiger: Perl 코드의 자동 현대화 프로젝트. 웹 프론트가 없어 로컬 설치 필요. Perl 정규식을 Raku로 번역하는 별도 프로그램을 포함. https://github.com/Util/Blue_Tiger/
- Perlito: 온라인 번역기! Perl 크로스 컴파일러 모음으로 Perl→Raku 번역 포함. 웹 프론트가 있어 설치 없이 사용 가능. 아직 Perl 문법의 일부만 지원. https://fglock.github.io/Perlito/perlito/perlito5.html
- Perl-ToPerl6: 고 Jeff Goff의 Perl::ToPerl6 모듈. 최소 변경으로 Perl을 컴파일 가능한 Raku 코드로 변환하는 걸 목표.