クトゥルフの方法の解析に対する議論は何ですか?


24

会社にとって非常に重要になる可能性のあるツールのために、ドメイン固有言語を実装するタスクを割り当てられました。この言語は単純ですが、些細なことではなく、ネストされたループ、文字列の連結などを既に許可しており、プロジェクトが進むにつれて他の構成要素が追加されることは実質的に確実です。

レクサー/パーサーを手書きで書くことは(文法が簡単でない限り)時間がかかり、エラーが発生しやすいプロセスであることを経験から知っています。そのため、yaccのパーサージェネレーターまたはParsecのような組み合わせライブラリーという2つのオプションがありました。前者も同様に優れていましたが、さまざまな理由で後者を選び、関数型言語でソリューションを実装しました。

結果は私の目にはかなり壮観で、コードは非常に簡潔で、エレガントで読みやすく/流fluentです。java / c#以外でプログラミングしたことがない場合、少し奇妙に見えるかもしれないと思いますが、java / c#で書かれていないものには当てはまります。

しかし、ある時点で、文字通り同僚に攻撃されました。私の画面を一目見た後、彼はコードが理解不能であり、解析を再発明するのではなく、誰もがするようにスタックとString.Splitを使用するだけだと宣言しました。彼は多くの騒ぎをしました、そして、私は彼を納得させることができませんでした、私が彼を信じることができませんでした 私は彼に言語を説明することさえ申し出ましたが、役に立ちませんでした。

私は議論が経営陣の前で再浮上することを確信しているので、いくつかの確固たる議論を準備しています。

これらは、String.Splitベースのソリューションを回避するために頭に浮かんだ最初のいくつかの理由です。

  • 特殊なケースや物事を迅速に制御不能にするには、多くのifが必要です
  • 多数のハードコードされた配列インデックスにより、メンテナンスが困難になります
  • メソッドの引数として関数呼び出しのようなものを処理することは非常に困難です(例:add((add a、b)、c)
  • 構文エラーの場合に意味のあるエラーメッセージを提供することは非常に困難です(発生する可能性が非常に高い)
  • 私はすべて単純さ、明快さ、そして不必要なスマート暗号のようなものを避けるためにいますが、バーガーフリッパーでも理解できるようにコードベースのすべての部分を馬鹿にすることは間違いだと思います。インターフェースを使用しない、懸念事項の分離を採用しない、コードをコピーアンドペーストするなど、私が聞いたのと同じ議論です。結局、ソフトウェアプロジェクトに取り組むには、最低限の技術的能力と学習意欲が必要です。(この議論はおそらく不快に聞こえるかもしれませんが、戦争を開始しても誰も助けにはなりません)

クトゥルフの方法を解析することに対するあなたの好きな議論は何ですか?*

*もちろん、彼が正しいと私を納得させることができれば、私も完全に幸せになります


9
あなたの同僚があなたのためにDSLプロジェクトを行うことを志願しているように思えます!
グランドマスター

23
「私はパース改革ちょうどスタックとのstring.Split皆がするように使うべきではない」 -気に、その男は無知が怪我をしないことを喜んでいる必要があります...
マイケルBorgwardt

4
同僚がドラゴンブック全体を読んでテストに合格しない限り、この議論に戻らないようにアドバイスします。そうでなければ、彼は構文解析関連の何かについて議論する権利がありません。
SKロジック

4
申し訳ありませんが、誰が解析を再発明しましたか?
rwong

2
「文字通り」という言葉を比someone的に使っている人を見かけたら、私の頭は文字通り爆発するでしょう。

回答:


33

2つのアプローチの決定的な違いは、彼が唯一の正しい方法であると考えているアプローチは必須であり、あなたのアプローチは宣言的であることです。

  • アプローチは明示的にルールを宣言します。つまり、文法のルールは(ほとんど)コードで直接エンコードされます。パーサーライブラリは、状態などの扱いにくいものを処理しながら、生の入力を解析済みの出力に自動的に変換します。コードは、抽象化の単一のレイヤー内に記述されます。これは、問題の領域である構文解析と一致します。parsecの正確性を想定するのは合理的です。つまり、ここでエラーが発生する唯一の余地は、文法の定義が間違っているということです。ただし、完全に修飾されたルールオブジェクトがあり、それらは単独で簡単にテストできます。また、成熟したパーサーライブラリには、エラー報告という重要な機能が1つ付属しています。解析が失敗した場合の適切なエラー回復は簡単ではありません。証拠として、PHPのparse error, unexpected T_PAAMAYIM_NEKUDOTAYIM:D を呼び出します

  • 彼のアプローチは、文字列を操作し、明示的に状態を維持し、生の入力を解析された入力に手動で持ち上げます。エラー報告など、すべてを自分で作成する必要があります。そして、何かがうまくいかないとき、あなたは完全に失われます。

皮肉なことに、あなたのアプローチで書かれたパーサーの正確性は比較的簡単に証明されます。彼の場合、それはほとんど不可能です。

ソフトウェア設計を構築するには、2つの方法があります。1つは明らかに欠陥がないように単純にすること、もう1つは明白な欠陥がないように複雑にすることです。最初の方法ははるかに困難です。

カーホア

あなたのアプローチ簡単です。それが除外するすべては、彼が彼の地平線を少し広げることです。彼のアプローチの結果は、あなたの地平線がどれほど広くても常に複雑になります。
正直に言うと、その男は無知な愚か者であり、ブラブ症候群に苦しんでおり、あなたが間違っていると思い込み、あなたが理解していないと怒鳴るほどrog慢です。

しかし、最終的に問題は、誰がそれを維持する必要があるのか​​ということです。それがあなたなら、それはあなたの電話です、誰が言っても。彼になる場合は、2つの可能性しかありません。パーサーライブラリを理解させる方法を見つけるか、彼のために命令型パーサーを作成する方法を見つけてください。パーサー構造から生成することをお勧めします:D


2つのアプローチの違いの優れた説明。
smarmy53

6
プログラマー向けTVTropesにリンクしているようです。さようなら午後...
イズカタ

10

解析式の文法(Packratパーサーアプローチなど)またはパーサーコンビネーターは、解析を再発明していません。これらは関数型プログラミングの世界で確立された手法であり、右手では、他の手法よりも読みやすくなります。数年前にC#でPEGのかなり説得力のあるデモンストレーションを見てきましたが、実際にそれは比較的単純な文法の最初の手段となります。

パーサーコンビネーターまたはPEGを使用したエレガントなソリューションがある場合は、比較的簡単に販売できるはずです:かなり拡張性があり、通常、関数型プログラミングへの不安を克服すると比較的読みやすくなり、通常のパーサージェネレーターより読みやすい場合もありますツールが提供しますが、それは文法とどちらかのツールセットでの経験のレベルに大きく依存します。また、テストの作成も非常に簡単です。もちろん、最悪の場合のシナリオではかなりひどい解析パフォーマンス(またはPackratでの大量のメモリ消費)を​​もたらす可能性のあるいくつかの文法のあいまいさがありますが、平均的な場合はかなりまともであり、実際にはいくつかの文法のあいまいさはLALRよりもPEGで処理されます思い出します。

Splitとスタックの使用は、PEGよりも単純な文法で動作するか、サポートできますが、時間が経つにつれて、再帰降下をひどく再発明するか、バンドの動作が不安定になる可能性が高くなります。非常に構造化されていないコードを犠牲にして提出を支援します。単純なトークン化ルールしかない場合、おそらくそれほど悪くはありませんが、複雑さを増すにつれて、おそらく最も保守性の低いソリューションになります。代わりにパーサージェネレーターにアクセスします。

個人的に、DSLを構築する必要があるときの最初の傾向は、Boo(.Net)やGroovy(JVM)のようなものを使用することです。なぜなら、マクロと簡単な調整を構築することで、既存のプログラミング言語と信じられないほどのカスタマイズ性のすべての強みを得るからですコンパイラパイプラインへ。ゼロから始めた場合、ループ、変数、オブジェクトモデルなどのように面倒な作業を実装する必要はありません。もしRubyやLispの開発をしている店にいたら、そこで意味のあるイディオム(メタプログラミングなど)を使うだけです。

しかし、あなたの本当の問題は文化かエゴのどちらかだと思います。AntlrまたはFlex / Bisonを使用していた場合、同僚も同じように驚いたことはないでしょうか?私はあなたの解決策を「主張する」ことは負けの戦いかもしれないと疑っています。地元の管理当局に訴えるのではなく、コンセンサス構築技術を使用するよりソフトなアプローチを行うためにより多くの時間を費やす必要があるかもしれません。プログラミングをペアリングし、保守性を犠牲にすることなく文法の調整をどれだけ迅速に行うことができるかを示し、テクニックやその歴史などを説明するためにブラウンバッグを行うと、10箇条書きと「失礼なQ&A」対決会議。


9

私は解析アルゴリズムなどに精通していませんが、プリンの証拠は食べることにあると思います。したがって、他のすべてが失敗した場合、パーサーを自分の方法で実装するように彼に提供できます。それから

  • いずれかのソリューションに費やされた時間を比較し、
  • 包括的な受け入れテストを通じて両方のソリューションを実行して、どちらのバグが少ないかを確認します。
  • 独立した裁判官に、サイズと明確さの結果のコードをあなたのものと比較させます。

テストを本当に公平にするために、両方のソリューションに同じAPIを実装し、共通のテストベッド(または両方の既知の単体テストフレームワーク)を使用することができます。どちらも、任意の数と種類の機能テストケースを記述し、彼自身のソリューションがそれらすべてに合格することを確認できます。そしてもちろん、理想的には、締め切り前にあなたのどちらも相手の実装にアクセスするべきではありません。決定的なテストは、他の開発者が開発したテストスイートを使用して両方のソリューションをクロステストすることです。


これは素晴らしいアイデアです!commontユニットテストフレームワークも簡単に使用できます。
smarmy53

1
同僚に分割バージョンを作成してもらうための+1 ... OPはそれを作成するタスクでした。だから彼は同僚ではなく、それをサポートする必要がありそうな人です。彼に他の作品の上にそれを提案するだけで、彼をあなたの背中から引き離すのに十分かもしれません。
イズカタ

7

技術的な質問があるかのようにこれを尋ねましたが、おそらく既に知っているように、ここには技術的な質問はありません。あなたのアプローチは、キャ​​ラクターレベルで何かをハックするよりもはるかに優れています。

本当の問題は、あなたの(おそらく経験豊富な)同僚が不安であり、あなたの知識に脅かされていると感じることです。 あなたは技術的な議論で彼を説得しません ; それは彼をより防御的にするだけです。代わりに、彼の恐怖を和らげる何らかの方法を見つけなければなりません。私は多くの提案を提供することはできませんが、レガシーコードに関する彼の知識を高く評価してみてください。

最後に、マネージャーが彼の専門的な議論に同意し、ソリューションを破棄した場合、別のポジションを探す必要があると思います。明らかに、より洗練された組織では、あなたはより価値があり、より高く評価されます。


私のアプローチが優れていることはすでに知っていましたが、良い説得力のある説明を出すことができませんでした-それは私が探している技術情報です。問題の「人間の相互作用」側が技術的なものと同じくらい重要であることに同意します(それ以上ではないにしても)。
smarmy53

4

簡単に説明します。

クトゥルフの方法を解析するのは難しいです。それはそれに対する最も単純で最も説得力のある議論です。

単純な言語のトリックを行うことができます。たとえば、通常の言語。ただし、正規表現よりも簡単ではないでしょう。

また、もう少し複雑な言語のトリックを行うこともできます。

ただし、ネスト、または単に「有意にステートフル」な数式、または例(ネストされた関数呼び出し)のある言語のCthulhuパーサーを見たいです。

誰かがそのような(非自明なコンテキストフリーの)言語のパーサーをクトゥルフしようとした場合に何が起こる想像してみてください。彼が正しいパーサーを書くのに十分賢いなら、私はコーディング中に最初のトークン化を「発見」し、次に何らかの形で再帰降下構文解析を行うだろうと思います。

その後、物事は簡単です:「おい、あなたは再帰降下パーサーと呼ばれるものを書いた!正規表現のように、単純な文法記述から自動的に生成できることを知っているかい?


長い話:
誰かが文明的なアプローチを使用するのを止めることができる唯一のことは、それに対する彼らの無知です。


1

おそらく、適切なDSLセマンティクスに取り組むことも重要です(構文が重要ですが、セマンティクスも重要です)。これらの問題に慣れていない場合は、Programming Languages Pragmatics(by M.Scott)やChristian Queinnec などの本を読むことをお勧めします。Lisp In Small Pieces。1996年ケンブリッジ大学出版局。

DSL2011などの DSL会議で最近の論文を読むことも役立ちます。

ドメイン固有言語の設計と実装は困難です(そしてほとんどの困難は構文解析ではありません!)。

クトゥルフの方法を解析することであなたが意味することは本当に理解できません; どういうわけか奇妙な方法で解析することを意味していると思います。


良いリンク。クトゥルフについては、申し訳ありませんが、リンクを忘れました。これは、古典的なcodinghorror記事への参照です:codinghorror.com/blog/2009/11/parsing-html-the-cthulhu-way.html。元の投稿を更新しました。
smarmy53
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.