if()の遅延評価を実装する方法


10

私は現在、以下に基づいて式エバリュエーター(式のような単一行式)を実装しています。

  • 入力された式は、リテラルブール、整数、小数、文字列、関数、識別子(変数)を分離するためにトークン化されます
  • シャンティングヤードアルゴリズムを実装し(可変数の引数を持つ関数を処理するように少し変更)、括弧を取り除き、適切な優先順位で演算子を後置された順序で並べます
  • 私のシャンティングヤードは、トークンの(シミュレートされた)キューを単に生成します(配列によって、Powerbuilder Classic言語はオブジェクトを定義できますが、ネイティブストレージとしてのみ動的配列を持ちます-真のリストではなく、ディクショナリーではありません)。シンプルなスタックマシン

私の評価者はうまく働いていますが、私はまだ足りないので、if()どうすればいいのか迷っています。

私のシャンティングヤードのポストフィックスおよびスタックベースの評価if()で、trueとfalseの部分を持つ別の関数として追加すると、1つif(true, msgbox("ok"), msgbox("not ok"))で両方のメッセージが表示され、1つだけ表示したいとします。これは、関数を評価する必要がある場合、その引数はすべて評価済みでスタックに配置されているためです。

if()怠惰な方法で実装する方法を教えてもらえますか?

私はこれらを一種のマクロとして処理することについて考えましたが、初期の段階ではまだ条件の評価ができていません。おそらく、キューとは別の種類の構造を使用して、条件とtrue / false式を別々に保持する必要があるのでしょうか?現時点では、式は評価前に解析されますが、将来の評価のために中間表現を一種のプリコンパイルされた式として保存することも計画しています。

編集:問題について少し後で、私は自分の式のツリー表現(線形トークンストリームの代わりにAST)を構築でき、そこから自分のの別のブランチを簡単に無視できると思いif()ます。

回答:


9

ここには2つのオプションがあります。

1)if関数として実装しないでください。特別なセマンティクスを持つ言語機能にします。簡単ですが、すべてを機能にしたい場合は、「純粋」ではありません。

2)「名前で呼び出す」セマンティクスを実装します。これははるかに複雑ですがif、言語要素の代わりに関数として保持しながら、コンパイラーマジックで遅延評価問題を処理できます。こんなふうになります:

if2つのパラメーターを受け取る関数で、どちらも「名前で」宣言されています。コンパイラがby-nameパラメータに何かを渡していることを検出すると、生成されるコードを変更します。式を評価して値を渡す代わりに、式を評価するクロージャーを作成し、代わりに渡します。また、関数内でby-nameパラメーターを呼び出すと、コンパイラーはクロージャーを評価するコードを生成します。


よくわかりませんが、「閉鎖」を「サンク」にするべきでしょうか。うーん、そうではないかもしれません。ウィキペディアのページを見たところ:「サンクはパラメーターのないクロージャーです」。

「名前で呼ぶ」と言うとき、グローバルに言及しているのですか?名前によるグローバルな呼び出しの代わりに、クロージャタイプを実装するだけで、if関数は3つのクロージャを取り、2つ(条件とthenまたはelse)を評価しますが、完全なcall-by-byなどのクロージャとしてすべてを認識する必要はありません。名前のセマンティクス
Jimmy Hoffa 2013年

@マット:「サンク」という用語はプログラミングの文脈で他のいくつかのことを意味する可能性があり、「パラメーターなしのクロージャー」は、私がそれを聞いたときに最初に考えるものではありません。「クロージャー」はもっと明確です。
メイソンウィーラー

1
@JimmyHoffa:「名前で呼び出す」と言うときは、関数の引数を設定する特定のスタイルを指しますが、これはオプションである必要があります。多くの既存の言語では、値渡しまたは参照渡しでパラメーターを渡すことを選択できるように、このシナリオでは、名前渡しを選択する必要があります。
メイソンウィーラー、

「名前で呼び出す」セマンティクスについての提案からいくつかの興味深い点がわかりましたが、関数の呼び出しが単一行であるため、完全なコンパイラではない評価者にとっては少しやりすぎです(MS-Excelの数式について考えてみてください)。呼び出しツリーを推定するためにスタックの疑似評価を行うことにより、トークンのキューイングの後にステップを追加できると考えています。破棄する枝をツリーから簡単に知ることができます。

3

シグネチャを持つ関数ではなく:

object if(bool, object, object)

署名を付ける:

object if(bool, object function(), object function())

次に、if関数は条件に基づいて適切な関数を呼び出し、そのうちの1つのみを評価します。


1

すべてをレイジーにコンパイルすれば、それは非常に簡単です。値がすでに評価されているかどうか、またはさらに評価が必要かどうかを確認する手段が必要です。

次に、以下を実行できます。リテラルまたは変数の場合(それらはありますか?つまり、関数の名前ですか?)、スタックにプッシュします。関数のアプリケーションの場合は、個別にコンパイルし、エントリポイントをスタックにプッシュします。

したがって、プログラムの実行は、スタックではなく関数が評価されるまでループするだけです。評価されていない場合、または関数の場合は、スタックの先頭が指すコードを呼び出します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.