takt式マニアクス①
生産スケジューラFLEXSCHE GPでは様々な場面でtakt式という計算式を使うことができます。 例えば、作業時間がどれくらいかかるか設定するのにtakt式で記述する、といった具合です。
このtakt式ですがFLEXSCHE内だけで使える独自言語で、いろいろな言語の要素が組み合わされていて、なんか見たことあるけどちょっと違う、なつかしさと新しさを一挙に味わえる素敵な言語です。 ただ言語と言ってもプログラミングのように制御構造を書くわけではなくて、あくまで様々なところで使う値を計算する「計算式」を書くためのものです。 単純な数値の四則演算だけではなく、FLEXSCHE内のデータにアクセスしてプロパティで値を取得したり、メソッドで計算させたりすることができます。
例えばガントチャート上で作業の表示文字列に前工程の作業の終了予定日時を出したい場合には、表示文字列の設定で計算式を指定して、
.LinkOperation(LinkKey.Input).ManufactureEndTime
と書きます。"."はオブジェクトに対するアクセス演算子で、その後ろにそのオブジェクトへのプロパティやメソッドを書いて呼び出すことができます。 .LinkOperationの先頭の"."はこの計算式の暗黙のコンテクストオブジェクト、ここでは表示する対象の作業、に対するアクセス演算子です。
つまりこの計算式を紐解くと以下のようになります。
[この作業].<リンク作業(入力)を取得>.<作業の製造終了日時を取得>
これがtakt式の基本的な使い方なのですが、ここからはちょっとマニアックな使い方をご紹介します。 題して「takt式マニアクス」。今日はその第一弾です。
別にこれが理解できなくても、使いこなせなくても、FLEXSCHEは十分に活用できます。 ただ、使いこなせると計算式がシンプルに書けたり、他のユーザーに一目置かれたりします。
では早速。
takt式では普通に四則演算をしたり、関数を呼び出したりするだけでなく、変数を定義することができます。 途中まで計算した値を複数の個所で利用したい場合には変数に保持しておけば計算量も記述量も減ります。
例えば先ほどの前工程の作業の終了予定日時を出す計算式に開始予定日時も追加したい場合、
$linkop := .LinkOperation(LinkKey.Input),
$linkop.ManufactureStartTime + "-" + $linkop.ManufactureEndTime
のように前工程の作業を一時変数に受けることですっきりと書けますし効率もよくなります。
この変数ですが、値やオブジェクトだけでなくなんと関数も保持することができます。
一つの計算式の中で同じ関数の呼び出し方をしているところが複数個所ある場合には、それを関数として定義して呼び出すことでシンプルに書くことができます。 例えば、先行作業と特定の仕様のコメントを比較する場合、
.Spec("hoge").Comment("hogehoge") = .PrecedingOperation.Spec("hoge").Comment("hogehoge")
と書けますが、作業に対して同じ関数の呼び出しが繰り返されています。これを関数定義を使うことで
$getSpecComment := Operation[.Spec("hoge").Comment("hogehoge")],
.$getSpecComment() = .PrecedingOperation.$getSpecComment()
とまとめることができます。この例ではそれほどメリットは感じられないかもしれませんが、式がより複雑になった場合には記述がシンプルになって保守性も高まることが容易に想像がつきますね。
関数定義のシグネチャは
Type(Type p1, Type p2, Type p3....)[Expression]->Type
となっていて、先頭の"Type"はアクセスする対象が必要ない場合には省略します。 引数がない場合には"()"とその中身も省略することができます。最後の"->Type"も戻り値の型を明示的に指定せずに計算式の中身から推測してもよい場合には省略できます。
ここからがマニアックポイント。この関数定義ですが、実は再帰関数も定義することができます。
例えばフィボナッチ数を計算する関数は以下のように書けます。
$fibonacci := (Long n)[$n <= 1 ? $n : $fibonacci($n - 2) + $fibonacci($n - 1)]->Long,
$fibonacci(10)
同じことを関数を複数定義して相互再帰で書くこともできます。
$fib1 := (Long n)[$n <= 1 ? $n : $fib1($n - 1)]->Long,
$fib2 := (Long n)[$n <= 1 ? $n : $fib1($n - 1) + $fib2($n - 1)]->Long,
$fib1(10)
FLEXSCHE内でどんなふうにこの再帰関数が利用できるかというと、例えば作業のリンクをたどって情報を収集したいときに、深さがあらかじめわかっていれば関数を繰り返し並べて書けばよいわけですが、わかっていない場合でも再帰関数を使うことで汎用的に記述することができます。
いかがだったでしょうか。以上で第一回のマニアクスは終了です。 これからもさらにマニアックな情報を提供するつもりなのでお楽しみに。