トラック
/
Factor
Factor
/
演習
/
リーアの絶品ラザニア
リーアの絶品ラザニア

リーアの絶品ラザニア

学習演習

はじめに

Cargo Shuffleでは、Factorのデータスタックと、それを並べ替えるシャッフルワードを学びました。この演習はその続きです。今回は、入力をただ動かすのではなく、入力を使って計算するワードを定義します。

コメント

!は行コメントの始まりです。Factorは!から行末までのすべてを無視します。以下の例では、!をコードの動作を説明するためと、出力される内容を示すための両方に使っています。

ワード

ワードは、Factorで関数を表す名前です。ワードを呼び出すと、スタックの一番上からいくつかの値が取り出され、代わりにいくつかの値が積まれます。.は一番上の値を取り出して表示します。整数演算のワード+、-、*は、2つの数値を取り出して結果を積みます。

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はそれらを使いません。Factorが追跡するのは、スタック上で値が並ぶ順序だけです。

! + is specified as ( x y -- sum )
! . is specified as ( x   --     )

スタックの一番上は右側の入力です。つまり、8 3 -では3が一番上にあるので、スタック効果は( x y -- difference )となり、結果は8 - 3です。

出力の末尾の?は「真偽値」を表す慣習です。ただし、ラザニアの演習では数値しか使いません。

このあと、Cargo Shuffleで登場したシャッフルワードが1つ出てきます。swap ( x y -- y x )です。これは、次のワードにとってスタック上位2つの値の順序が都合が悪いときに、それらを入れ替えます。

ワードを定義する

:でワードの定義を始めます。次にスタック効果、その後に本体を書き、;で終わります。

: square ( x -- x^2 ) dup * ;

4 square .    ! => 16

Factorのコンパイラーは、本体が宣言されたスタック効果と実際に合っているかを検査します。( x -- y )と宣言しながら、スタックに値を0個または2個残すワードはコンパイルされません。

定数

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

説明

この演習では、お気に入りの料理本から最高のラザニアを作れるように、コードを書いていきます。

ラザニアの調理にかかる時間に関する、4つのタスクがあります。

1. 想定される焼き時間を定数に保存する

expected-bake-timeという定数を定義します。これは、ラザニアをオーブンで焼くのに何分かかるかを返すようにします。

料理本によると、ラザニアはオーブンで合計40分焼く必要があります。

expected-bake-time .
! => 40

2. 準備時間を分単位で計算する

preparation-timeというワードを定義します。これは、ラザニアに重ねた層の数をスタックから取り出し、準備にかかった分数をスタックに残します。1層の準備に2分かかるものとします。

4 preparation-time .
! => 8

3. 残りの焼き時間を分単位で計算する

remaining-timeというワードを定義します。これは、ラザニアがすでにオーブンで焼かれていた分数を取り出し、あと何分オーブンに残す必要があるかをスタックに残します。

25 remaining-time .
! => 15

4. 合計作業時間を分単位で計算する

total-working-timeというワードを定義します。これは、スタックから2つの引数(まずラザニアの層の数、次にラザニアがすでにオーブンにあった分数)を取り出し、これまでに調理にかかった合計時間(準備時間とすでにオーブンにあった時間を合わせたもの)をスタックに残します。

3 20 total-working-time .
! => 26
GitHubで編集する リンクは新しいウィンドウまたはタブで開きます
Factor Exercism

リーアの絶品ラザニアを始める準備はできましたか?

Exercismに登録すれば、47個のコンセプト163個の演習、そして本物の人間によるメンタリングとともに、Factorを学んでマスターできます。すべて無料です。