Fluent APIで自然言語の文法を使用する


14

私はWebSQL / Phonegap Database APIのクエリ抽象化をいじっていますが、自然な英語の文法の使用を模倣する流なAPIを定義することに惹かれ、疑っています。

これを例で説明するのが最も簡単かもしれません。以下は私の文法におけるすべての有効なクエリであり、コメントは意図したセマンティックを説明しています:

//find user where name equals "foo" or email starts with "foo@"
find("user").where("name").equals("foo").and("email").startsWith("foo@")

//find user where name equals "foo" or "bar"
find("user").where("name").equals("foo").or("bar");

//find user where name equals "foo" or ends with "bar"
find("user").where("name").equals("foo").or().endsWith("bar");

//find user where name equals or ends with "foo"
find("user").where("name").equals().or().endsWith("foo");

//find user where name equals "foo" and email is not like "%contoso.com"
find("user").where("name").equals("foo").and("email").is().not().like("%contoso.com");

//where name is not null
find("user").where("name").is().not().null();

//find post where author is "foo" and id is in (1,2,3)
find("post").where("author").is("foo").and("id").is().in(1, 2, 3);

//find post where id is between 1 and 100
find("post").where("id").is().between(1).and(100);

Quentin Pradetのフィードバックに基づいて編集:さらに、APIは複数形と単数形の両方の動詞形式をサポートする必要があるようです。

//a equals b
find("post").where("foo").equals(1);

//a and b (both) equal c
find("post").where("foo").and("bar").equal(2);

質問のために、ここですべての可能な構成を使い尽くしていないと仮定しましょう。また、ほとんどの正しい英語の文章をカバーできると仮定しましょう。結局のところ、文法自体はSQLで定義された動詞と結合語に限定されています。


グループ化に関する編集:1つの「文」は1つのグループであり、優先順位はSQLで定義されているとおりです(左から右)。複数のwhereステートメントで複数のグループを表現できます。

//the conjunctive "and()" between where statements is optional
find("post")
  .where("foo").and("bar").equal(2).and()
  .where("baz").isLessThan(5);

あなたが見ることができるように、各メソッドの定義は、それがである文法文脈に依存している。例えば、「連動方法」への引数or()and()いずれかのうち、左、することができますまたはフィールド名を参照するか、期待値。

私にはこれは非常に直感的に感じますが、あなたのフィードバックを聞きたいです:これは良い、便利なAPIですか、それとももっと簡単な実装に戻るべきですか?

記録用:このライブラリは、構成オブジェクトに基づいた、より従来型の非流APIなAPIも提供します。


1
連鎖は、jQueryが非常に有名な理由でもあります。かなり簡単で、シーケンシャルで、理解しやすい。
ジョセフ

3
これは面白い!おそらくプログラマーにこれを尋ねるべきでしょう。
ベンジャミングリュンバウム

2
グループ化はどのように処理しますか?以下と同等:... where foo = 1 or (bar = 2 and qux = 3)

7
IMOこの種の流APIなAPIは恐ろしいです。たとえば、演算子の優先順位の欠如は迷惑です。where("name").equals("foo").or("bar")として解析し(name=="foo")or barます。その後、文字列がリテラルを表すとき、および列名を表すときは明確ではありません
...-CodesInChaos

4
ところで。データベースのクエリにDSLを使用する場合は、SQLと呼ばれる既存のDSLを使用できます。
CodesInChaos

回答:


23

それは非常に間違っていると思います。私は自然な言語を勉強しますが、文脈と多くの人間の知識でしか解決できない曖昧さに満ちています。プログラミング言語が曖昧でないという事実は非常に良いことです!コンテキストに応じてメソッドの意味を変更したいとは思わない:

  • あいまいさをもたらすため、これは驚きを追加します
  • ユーザーは、カバーしていない構造を使用したいと思うでしょう。 find("user").where("name").and("email").equals("foo");
  • エラーを報告するのは難しいです:あなたは何ができますfind("user").where("name").not().is().null();か?

また、ほとんどの正しい英語の文章をカバーできると仮定しましょう。結局のところ、文法自体はSQLで定義された動詞と結合語に限定されます。

いいえ、ほとんどの正しい英語の文章をカバーすることはできません。他の人は以前に試しましたが、非常に複雑になります。それは自然言語理解と呼ばれますが、誰もそれを実際に試みません。最初に小さな問題を解決しようとしています。ライブラリには、基本的に2つのオプションがあります。

  • 英語のサブセットに自分自身を制限するか、SQLを提供するか、
  • または、「英語」をカバーしようとすると、言語のあいまいさ、複雑さ、および多様性のために不可能であることがわかります。

ご意見ありがとうございます。リストした最初のケ​​ースをカバーするように私の質問を編集し、いくつかの警告を追加しました。あいまいさに関するあなたの立場に同意します-それが私の質問の核心です。プログラミング言語が明確に定義されたコンテキストで曖昧であることは許容されますか?
フェンクリフ

あいまいな場合、明確に定義されていません。あいまいな場合、複数の潜在的な結果があり、何かがそれらの1つを選択する必要があります。選択は明確に定義されるか、言語パーサーがランダムに選択します。したがって、プログラミング言語の曖昧さは、決定論的(1 + 1は常に2に等しい)ではなく、確率的言語(1 + 1は2に等しい場合があり、1または3に等しい場合があります)が必要な場合は問題ありません。
マイケルポールコニス

彼の提案や英語について話しているのですか?ほとんどの場合、あいまいさはコンテキストや知識(その一部は常識です)を使用して解決できますが、これはコンピューターでは利用できません。
クエンティンプラデ

+1流APIなAPIの特定の実装のコンテキスト依存性に関する良いキャッチ。彼の流APIなAPIのアイデアは一見したところ好きでしたが、これを見るのにあまりよく見ていませんでした。間違いなく大きな問題。
ジミー・ホッファ

彼が文法を明確にし、文脈を自由にするなら、問題は何ですか?確かに、動詞の複数形の単数形とそのようなものを削除したいかもしれませんが、それは彼らがやろうとしていたことの核心を変えません。持っていないis()か、それequal()だけequals()です。この後のエラーの報告に関する問題は表示されません。null()また、構文関数ではなく、比較対象のリテラルになります。find("user").where("name").is().not().null();になるfind("user").where("name").not().equals(null);
-whn

3

私は、これが素晴らしいデザインではないという他の人の投稿に多少同意する傾向があります。ただし、別の理由があると思います。

SQLクエリの具体的な構文として私が見ているものを提示しています。具体的な構文は言語を決して助けにはならず、それが悪い場合にのみ傷つくと私は強く信じています

ただし、抽象構文は別の話です。抽象構文は、言語の構造と、フレーズを組み合わせてより大きなフレーズを作成する方法を定義します。言語の成功は、抽象構文定義の品質に強く依存していると感じています。

流れるようなAPIでの私の問題は、曖昧であったり、不明瞭であったり、表現力に欠けたりすることではなく、実際の言語とその構造を隠し、そうすることで、物事が必要以上に複雑になることです(あいまいさ、明白でない構文エラーなどを導入することによって)。

「従来型のAPI」も提供すると述べたので、これはすべて知っているようです。それに「いいね!」と言います。しかし、だからといって、流APIなAPIを並行して開発できないというわけではありません!1つの抽象構文定義で、複数の具象構文をサポートできます。抽象構文は本物であることに留意する必要がありますが、具体的な構文も非常に役立ちます。


2

クエンティン・プラデの非常に良い点に加えて、私はこの言語の恩恵を疑っています。

おそらく、自然言語に近い文法のポイントは、それをアクセス可能にすることです。しかし、SQLはすでに自然言語に非常に近いものです。これらの1つは他の1つよりも英語に本当に近いですか?

find("user").where("name").equals("foo")

select user from table where name = 'foo'

直感性や読みやすさの観点から、あなたの文法の利点は実際には見当たりません。実際、SQLバージョンは、その空白のために、より読みやすく見えます(入力しやすくなります)。


2

このAPIを検討する際に行われたと思われる、理想的な設計とは言えないほど多くの悪い決定があります。

1つ目は実用性の問題です。どのような目的に役立つのでしょうか?これは、SQLの方言にコンパイルされるデータ構造を作成しているようです。ちなみに、文法は限られたSQLのセットのようです。「SQLを使用するだけでどのような利点がありますか?」という質問 キーになります。適切な補間を使用して文字列を書き込むだけでなく、流れるようなインターフェイスを使用して書き込む方が面倒な場合、このAPIを使用して書き込むことはありません。

英語はあいまいです。英語で流interfaceなインターフェイスをモデル化しようとするのは適切ではありません(ラテン語を使用したほうがよいでしょう)。同じ一連の呼び出しの有効な解析が複数ある場合、混乱と驚きにつながります。これらのどちらも、APIに含めるのに適したものではありません。

このAPIが公開しているよりも多くのSQLの部分があります。結合(無数の形式のいずれか)は、サンプルセットには特にありません。サブクエリ(foo in (select id from bar))、ユニオン、およびgroup byは、よく使用されるものの一部です。ロジックの複雑なグループ化は、直感的な方法では存在しないようです。

このAPIを使用して記述していて、APIが目的のクエリを表現できないことがわかった場合、かなりの時間が失われます。アプリケーションでクエリを実行するために混合スタイルを使用することは適切ではありません(このAPIの単純なクエリ、生のSQLでは複雑です)。最終的には、より表現力豊かなスタイルが使用されます。

プログラミングは広まっていますが、英語は流notではありません。言語が「SQLライク」に制限されている場合でも、ネイティブスピーカーが何かを読み、第二言語または第三言語として英語を持っている人を読むには微妙な違いがあります。

英語のために、APIには不必要な冗長性があります。特に、equal()equals()同じことをやって。私はそれを確信しis()ていませんが、それは一致する英語に近いために追加されたノーオペレーションだと思います。チャットでルビーのメソッドの冗長性についての私の不平を聞くことを歓迎します-同じ間違いをしないでください。

座って、使用できるようにするクエリの包括的なサンプルセットを作成します。これらの例をすべて、クエリ自体よりも煩雑ではない明確な方法で誰が処理するかを決定します。それができない場合は、APIを書く道をたどる価値があるかどうかを検討してください。SQLは、数十年にわたる改良を経て今日に至りました(完璧ではありませんが、これ以上良いものは見つかりませんでした)。

RFC 1925-12のネットワークの真実

(12)プロトコル設計では、追加するものが残っていないときではなく、奪うものが残っていないときに完全に到達しました。

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