2つのバイナリ演算子opl
とopr
の-sameopl
の優先順位を持つプログラミング(またはスクリプト)言語(またはドメイン固有の言語)はありますか左結合であり、opr
は右結合ですか?
(私はそのような例を見つけることができませんが、私はその奇妙なケースを処理するのに十分な一般的なパーサーをコーディングしようとしています)
形式xopl
yopr
zまたはx = opr
yopl
z解析されますか?そして、より一般的にはさらに多くのオペランドがありますか?
独自の演算子を定義できる3つの言語を以下に示します。これらは2つ半異なることを実行します! HaskellとCoqはどちらもこの種の悪意のある行為を禁止していますが、異なっていますが、Agdaはこのような関連性の混合を許可しています。
まず、 Haskell では、単にこれを行うことはできません。 独自の演算子を定義して、優先度(0〜9)と選択した結合性を与えることができます。 ただし、Haskellレポート 結合性の混合を許可しません :
構文エラーを回避するために、同じ優先順位を持つ括弧で囲まれていない連続した演算子は、両方とも左または右のいずれかに結合する必要があります。 [Haskell 2010レポート、Ch。 3]
したがって、 [〜#〜] ghc [〜#〜] で、左結合(infixl
)演算子<@
と右結合演算子@>
を同じ優先レベルで定義すると、 – 0としましょう–次にx <@ y @> z
を評価するとエラーが発生します
優先解析エラー
同じ中置式で「<@
」[infixl 0
]と「@>
」[infixr 0
]を混在させることはできません
(実際、==
が構文エラーになるように、x == y == z
のように、演算子をインフィックスであるが非結合であると宣言することもできます。)
一方、依存型付けされた言語/定理の証明者 Agda があります(確かに、これはかなり主流ではありません)。 Agdaには、mixfix演算子をサポートする、私が知っているあらゆる言語の中で最も柔軟な構文があります。標準ライブラリには関数が含まれています
if_then_else_ : ∀ {a} {A : Set a} → Bool → A → A → A
呼び出されたときに書き込まれます
if b then t else f
アンダースコアを埋める引数で!これは、非常に柔軟な解析をサポートする必要があることを意味するので、これについて言及します。当然、Agdaには固定宣言もあり(その優先レベルは任意の自然数の範囲であり、通常は0〜100です)、Agdadoesにより、同じ優先順位で異なる固定性の演算子を混在させる。ただし、ドキュメントでこれに関する情報を見つけることができないため、実験する必要がありました。
上記の<@
と@>
を再利用しましょう。 2つの単純なケースでは、
x <@ y @> z
として解析x <@ (y @> z)
;そしてx @> y <@ z
を(x @> y) <@ z
として解析。私thinkAgdaが行うことは、行を「左連想」と「右連想」のチャンクにグループ化することです。右連想チャンクは、隣接する引数を取得する際に「優先順位」を取得します。それで私たちに
a <@ b <@ c @> d @> e @> f <@ g
として解析
(((a <@ b) <@ (c @> (d @> (e @> f)))) <@ g
または
しかし、私の実験にもかかわらず、私が最初にそれを書いたとき、私は間違っていると思いました、それは有益かもしれません:-)
(そして、Haskellと同様に、Agdaには非連想演算子があり、これは正しく解析エラーを与えるため、関連性が混在していると解析エラーが発生する可能性があります。)
最後に、theorem-prover/dependly-typed言語 Coq があります。これは、Agdaよりもさらに柔軟な構文です。これは、その構文拡張が実際に新しい構文構造の仕様を指定して実装し、それらをコア言語(漠然とマクロのようなものだと思います)。 Coqでは、リスト構文[1; 2; 3]
は標準ライブラリからのオプションのインポートです。新しい構文は変数をバインドすることさえできます!
ここでも、Coqで独自の中置演算子を定義し、優先レベル(主に0〜99)と関連性を与えることができます。ただし、Coqでは、各優先レベルは1つの関連性しか持てません。したがって、<@
を左結合として定義し、同じレベルで@>
を右結合として定義しようとすると(たとえば、50)、次のようになります。
エラー:レベル50はすでに左結合であると宣言されていますが、現在は右結合であることが期待されています
Coqのほとんどの演算子は、10で割り切れるレベルです。関連性の問題があった場合(これらのレベルの関連性はグローバルです)、通常はどちらかの方向(通常は上)にレベルを1つ上げます。
Douglas Crockfordによって普及したため、Prattパーサー(またはトップダウンオペレーター優先順位パーサー)がより一般的になり始めています。これらのパーサーは、ルールを固定文法に組み込むのではなく、演算子の優先順位と結合性の表から機能するため、ユーザーが独自の演算子を定義できる言語に役立ちます。
それらには、最初に式の左端の項を解析し、次に適切にバインドする限り、新しい演算子と右項を再帰的にバインドすることによって機能する解析関数があります。左結合演算子は、同じ優先順位までの優先順位を持つ右側の用語をバインドしますが、右結合演算子は、優先順位にのみバインドしますが、それを含めません。これにより、上記で引用したAgdaと同じ解析ツリーが生成されると思います。