트랙
/
Factor
Factor
/
연습 문제
/
리아의 맛있는 라자냐
리아의 맛있는 라자냐

리아의 맛있는 라자냐

학습 연습 문제

소개

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).

지침

이 연습 문제에서는 좋아하는 요리책을 보고 근사한 라자냐를 만들 수 있도록 코드를 작성해 볼 거예요.

라자냐를 요리하는 데 걸리는 시간과 관련된 네 가지 과제가 있어요.

1. 예상 굽기 시간을 상수에 저장하기

expected-bake-time 상수를 정의해요. 이 상수는 라자냐를 오븐에 굽는 데 몇 분이 필요한지 반환해야 해요.

요리책에 따르면 라자냐는 오븐에 총 40분 동안 있어야 해요.

expected-bake-time .
! => 40

2. 준비 시간을 분 단위로 계산하기

preparation-time 워드를 정의해요. 이 워드는 스택에서 라자냐에 추가한 층의 수를 꺼내요. 그리고 각 층을 준비하는 데 2분이 걸린다고 가정할 때, 준비에 걸린 시간(분)을 남겨요.

4 preparation-time .
! => 8

3. 남은 오븐 시간을 분 단위로 계산하기

remaining-time 워드를 정의해요. 이 워드는 라자냐가 오븐에서 이미 보낸 시간(분)을 꺼내고, 오븐에 앞으로 더 있어야 할 시간(분)을 남겨요.

25 remaining-time .
! => 15

4. 총 작업 시간을 분 단위로 계산하기

total-working-time 워드를 정의해요. 이 워드는 스택에서 두 개의 인자를 꺼내요. 첫 번째는 라자냐의 층 수이고, 두 번째는 라자냐가 오븐에 이미 있었던 시간(분)이에요. 그런 다음 지금까지 요리한 총 시간, 즉 준비 시간과 오븐에 이미 있던 시간을 더한 값을 남겨요.

3 20 total-working-time .
! => 26
GitHub에서 편집 링크가 새 창이나 탭에서 열려요
Factor Exercism

리아의 맛있는 라자냐 문제를 시작해 볼 준비가 됐나요?

Exercism에 가입하고 Factor 트랙을 개념 47개연습 문제 163개, 그리고 실제 사람의 멘토링과 함께 배우고 익혀 보세요. 모두 무료예요.