みんなに優しく、解りやすくをモットーに開設しています。 以下のルールを守りみんなで助け合いましょう。
1.ファイルメーカーで解らない事があればここで質問して下さい。 何方でも、ご質問・ご回答お願いします。 (優しく回答しましょう)
You are not logged in.
Pages: 1
http://filemaker-kou.seesaa.net/article/148132326.html
上記のURLに以下の式が書いてありましたが、どうも意味を理解できません。
Caseはわかりますが、tailの関数の意味が不明です。
どなたか、教えて頂けないでしょうか?
Case ( nmax > 1;
tail (num ; nmax-1) + 1;
num
)
以上、よろしくお願いします。
tail ( num ; max )
っていう名前のカスタム関数を例に再帰処理の説明ですね。
どのような内容のカスタム関数か説明がないと思うのですが????
質問の目的がよく分かりませんが、 とおりすがりさんが既に書かれていますが、
tail ( num ; nmax ) を例にした再帰処理の書き方で再帰回数の上限が変わる説明ですよね。
Case ( nmax > 0;
tail (num ; nmax-1) + 1;
num
)
こうした方がわかるかな...(テキトー)
num に nmax 回 、1 を足す。
説明のためのカスタム関数なので何に使えるかを考える必要はないでしょう。
実際作ってみれば分かると思いますがサンプル。(元の式を編集していません)
http://xfs.jp/3BHZ7
Offline
その式自体がtail()関数の定義だということがわからなかったのかな?
リンク先にEvaluateを使うのを「またフィールドとして定義する必要があり、カスタム関数に比べて呼び出しが面倒です。」と書いてありますけど、フィールドの必要は別にないですね。
「計算式を毎回書かずに呼び出す」のには必要かもしれませんが。
今のバージョンでは、フィールドでなくテキストオブジェクト(レイアウト外に置けば見えない)でも可能です。
書いた本人です。
雑な書き方でごめんなさい。
他の方が仰っているように、例示のコード自体がtail()の定義であり、
再帰呼び出し時の末尾最適化による上限の変化を示したものです。
「tail」という名称は末尾最適化の事例によく使われるもので、
それ自体には特に意味はありません。
-
scripterさん
> フィールドの必要は別にないですね。
この辺も雑でした。確かこの話題の前段のケースを処理する際に、
Evaluate()を使った方法ではフィールド定義が要る、だった気がします。
みなさん、ありがとうございます。
まだ、しっくりいかないですが、よく考えてみます。
カスタム関数の定義内で、当該カスタム関数を指定する事が出来るのですか?
これが、再帰という意味なのでしょうか?
> カスタム関数の定義内で、当該カスタム関数を指定する事が出来るのですか?
> これが、再帰という意味なのでしょうか?
はい、それが再帰という書き方です。
例えば以下を「tail」という名カスタム関数として登録します。
Case ( nmax > 1;
tail (num ; nmax-1) + 1;
num
)
tail関数の中でtail関数を呼び出している、この構造を再帰呼び出しと呼びます。
カスタム関数だけで何かを繰り返し処理したい場合、この再帰呼び出しを使う必要があります。
FileMakerで再帰呼び出しを扱う方法や要点は、
Web上に色々と解説もあるので、そちらを見た方が早いです。
末尾最適化だけ、あまり見かけないので、概念だけ少し平易に。
ある計算式の中で何か関数を呼んでいる場合、
その関数の結果を取得しなければ、計算式全体は終了できません。
Right( Left( Substitute( text; "foo"; "bar" ); 8); 3)
こんな計算式の場合、まずRight()を処理しようとしますが、
Right()を処理するためにはLeft()を処理する必要があり、
Left()を処理するにはSubstitute()を処理する必要があります。
雑に言うと、こんな感じです。
Right( //Right()を一旦止めて必要なLeft()の結果を待つ
Left( //Left()を一旦止めて必要なSubstitute()の結果を待つ
Substitute( text; "foo"; "bar" ); //Substitute()の結果を返す
8); //Substitute()の結果が返ったからLeft()の結果を返す
3)
//Left()の結果が返ったからRight()の結果を返す
つまり関数を呼び出す度に、一旦そこで待機しておき、
必要な関数の処理が終わるのを待ち受けなければなりません。
この待ち受けるための仕組に必要なコストは意外と大きいのですが、
上記のような一般的な構造の計算式なら問題にはなりません。
しかし再帰呼び出しの場合は大きな問題になります。
再帰呼び出しでは、無数に繰り返し関数の呼び出しが行われます。
foo(
foo(
foo(
foo(
foo(
foo(
foo(
...
)
)
)
)
)
)
)
例えば5000回の再帰呼び出しが行われれば、
5000回目を処理し終えるまで、1回目の呼び出しが終われません。
5000回目が終われば次は4999回目、次は4998回目...
という風に、膨大に積み残したまま計算を進めていくことになります。
この再帰呼び出しの問題を解消してくれるのが末尾最適化です。
そもそも1回目が2回目の完了を待つ必要がなく、
毎回ただ同じ関数を引数を変えて実行できれば、積み残すは不要です。
つまり、
tail (num ; nmax-1) + 1;
ではtail()の完了を待って+1する必要がありますが、
tail (num + 1; nmax-1);
なら、個々のtail()を毎回実行し、
最後のtail()の結果が再帰呼び出しの結果として扱えます。
こういった最適化はFileMakerの場合、ユーザーが明示的に行うものではありません。
計算式の構造をFileMakerが解析し、末尾最適化を行っても問題なければ、勝手に適用してくれます。
末尾最適化が効いても再帰呼び出し回数に上限はありますが、
上限が5倍に増え、負荷も小さい末尾最適化は、
再帰呼び出しを行うカスタム関数を書く場合望ましいものです。
かといって、再帰回数の上限が問題にならない場合に、
無理に末尾再帰で書こうとする必要はありません。
慣れるまでは再帰呼び出しそのものが扱いにくく、
末尾最適化まで意識すると大変かもしれません。
ある程度再帰呼び出しに慣れたら、既存のカスタム関数を、
末尾再帰に書き換えてみるぐらいが丁度よいかも知れません。
-
蛇足。
FileMakerの計算式やカスタム関数で用いられる言語は、
CやJavaScriptやGoなどの手続き型言語ではなく、不完全なある種の関数型言語です。
これはExcelの計算式と相同で、手続き型で言う変数は無く、
手続き文も持たず、中途半端なFRPっぽくもあります。
局所的で中途半端な純粋関数型言語と認識しておけば、
Let()の束縛や再帰の仕様も腑に落ち、少し不満が減ります。
丁寧に教えて頂きありがとうございます。
勉強させて頂きます。
Pages: 1
[ Generated in 0.023 seconds, 7 queries executed - Memory usage: 541.99 KiB (Peak: 562.9 KiB) ]