Cargo Shuffle에서 Factor의 데이터 스택과, 스택을 재배열하는 셔플 워드들을 만났어요. 이번 연습 문제는 그 위에 쌓여 있어요. 입력값을 이리저리 옮기기만 하는 대신, 입력값으로 계산을 하는 워드를 직접 정의해 볼 거예요.
!는 한 줄 주석을 시작해요. Factor는 !부터 그 줄 끝까지 전부 무시해요. 아래 예제들에서는 !를 코드가 무엇을 하는지 설명하는 데도 쓰고, 어떤 값을 출력하는지 보여 주는 데도 써요.
워드는 Factor에서 함수를 부르는 이름이에요. 워드를 호출하면 스택 맨 위에서 값 몇 개를 꺼내고, 다시 값 몇 개를 밀어 넣어요. .은 맨 위 값을 꺼내서 출력해요. 정수 산술 워드인 +, -, *는 숫자 두 개를 꺼내서 결과를 밀어 넣죠:
2 3 + . ! prints 5
8 3 - . ! prints 5 (8 - 3, not 3 - 8)
2 3 * . ! prints 6
이와 관련된 워드 .s는 아무것도 소비하지 않고 데이터 스택 전체를 출력해요. 리스너(Factor의 대화형 프롬프트로, 코드를 입력하면 결과를 볼 수 있어요)에서 코드 조각이 무엇을 남기는지 확인할 때 편리하죠. 뒤에 나오는 예제들이 . 대신 .s로 끝나는 경우가 있는 것도 그래서예요. 값이 하나보다 많이 남는데, .s는 그것을 전부 보여 주니까요.
산술 워드들은 math 보캐뷸러리에 있어요. 그래서 이것들을 사용하는 파일은 USING: 줄에 math를 넣어야 해요.
모든 워드는 ( inputs -- outputs ) 형태의 스택 효과와 함께 문서화되어 있어요. 이건 그 워드의 계약 같은 거예요. 이 워드는 스택 맨 위에서 입력값들을 꺼내고, 그 자리에 출력값들을 남겨요. 안에 적힌 이름들은 읽기 쉽도록 도와주는 역할만 해요. Factor는 그 이름들을 사용하지 않아요. 값들이 스택에서 놓인 순서만 따를 뿐이에요.
! + is specified as ( x y -- sum )
! . is specified as ( x -- )
스택의 맨 위가 오른쪽 입력값이에요. 그래서 8 3 -에서는 3이 맨 위에 있고, 스택 효과는 ( x y -- difference ), 결과는 8 - 3이에요.
출력 쪽에 ?가 붙는 것은 "불리언"이라는 뜻을 나타내는 관례예요. 다만 라자냐 연습 문제에서는 숫자만 사용해요.
아래에서는 Cargo Shuffle에 나온 셔플 워드 하나가 다시 등장해요. swap ( x y -- y x )인데, 다음 워드에 쓰기에 맨 위 두 값의 순서가 맞지 않을 때 이 둘을 뒤집어 줘요.
:는 워드 정의를 시작하고, 그다음에 스택 효과가 오고, 그다음에 본문이 오고, 마지막으로 ;가 정의를 끝내요.
: square ( x -- x^2 ) dup * ;
4 square . ! => 16
Factor의 컴파일러는 본문이 선언한 스택 효과와 실제로 맞는지 검사해요. ( x -- y )라고 해 놓고 스택에 값을 하나도 남기지 않거나 두 개를 남기는 워드는 컴파일되지 않아요.
CONSTANT:는 고정된 값에 이름을 붙여 줘요. 상수 자체도 하나의 워드예요. 호출하면 그 값이 스택에 올라가요:
CONSTANT: pi 3
pi pi * . ! => 9
CONSTANT:는 핵심 문법이라 USING: 줄이 필요 없어요. 상수는 파일 맨 위, 그 상수를 사용하는 워드보다 앞에 두세요.
워드의 본문에서는 이미 스코프 안에 있는 워드라면 무엇이든 호출할 수 있어요. 같은 파일에서 앞서 정의한 워드도 마찬가지고요:
: double ( x -- 2x ) 2 * ;
: quadruple ( x -- 4x ) double double ;
5 quadruple . ! => 20
연습 문제의 마지막 과제가 앞의 과제를 재사용하는 방식이 바로 이거예요.
워드와 상수는 모두 lowercase-kebab-case를 사용해요. 소문자들을 하이픈으로 이어 붙이는 방식이에요(예를 들어 expected-bake-time, preparation-time).
이 연습 문제에서는 좋아하는 요리책을 보고 근사한 라자냐를 만들 수 있도록 코드를 작성해 볼 거예요.
라자냐를 요리하는 데 걸리는 시간과 관련된 네 가지 과제가 있어요.
expected-bake-time 상수를 정의해요. 이 상수는 라자냐를 오븐에 굽는 데 몇 분이 필요한지 반환해야 해요.
요리책에 따르면 라자냐는 오븐에 총 40분 동안 있어야 해요.
expected-bake-time .
! => 40
preparation-time 워드를 정의해요. 이 워드는 스택에서 라자냐에 추가한 층의 수를 꺼내요. 그리고 각 층을 준비하는 데 2분이 걸린다고 가정할 때, 준비에 걸린 시간(분)을 남겨요.
4 preparation-time .
! => 8
remaining-time 워드를 정의해요. 이 워드는 라자냐가 오븐에서 이미 보낸 시간(분)을 꺼내고, 오븐에 앞으로 더 있어야 할 시간(분)을 남겨요.
25 remaining-time .
! => 15
total-working-time 워드를 정의해요. 이 워드는 스택에서 두 개의 인자를 꺼내요. 첫 번째는 라자냐의 층 수이고, 두 번째는 라자냐가 오븐에 이미 있었던 시간(분)이에요. 그런 다음 지금까지 요리한 총 시간, 즉 준비 시간과 오븐에 이미 있던 시간을 더한 값을 남겨요.
3 20 total-working-time .
! => 26
Exercism에 가입하고 Factor 트랙을 개념 47개연습 문제 163개, 그리고 실제 사람의 멘토링과 함께 배우고 익혀 보세요. 모두 무료예요.