Использование грамматики естественного языка в свободном API

14

Я возился с абстракцией запросов через API баз данных WebSQL / Phonegap, и я чувствую себя неуверенно и не в силах определить свободный 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);

Редактирование на основе отзывов Квентина Праде : Кроме того, похоже, что 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.


Редактировать в отношении группировки : одно «предложение» - это одна группа, и приоритет такой, как определено в 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 на основе объектов конфигурации.

fencliff
источник
1
Цепочка также является причиной того, что jQuery очень известен. Довольно простой, последовательный и понятный.
Джозеф
3
Это интересно! Вы должны спросить об этом у программистов.
Бенджамин Грюнбаум
2
Как бы вы справились с группировкой? Эквивалент: ... where foo = 1 or (bar = 2 and qux = 3)?
7
ИМО этот вид беглого API ужасен. Например, отсутствие приоритета оператора раздражает. Я бы разобрался where("name").equals("foo").or("bar")как (name=="foo")or bar. Тогда неясно, когда строка представляет литерал, а когда она представляет имя столбца, ...
CodesInChaos
4
Кстати. если вы хотите использовать DSL для запросов к базе данных, вы можете использовать уже существующий DSL под названием SQL.
CodesInChaos

Ответы:

23

Я думаю, что это очень неправильно. Я изучаю естественный язык, и он полон неоднозначности, которая может быть решена только с учетом контекста и большого количества человеческих знаний. Тот факт, что языки программирования не являются неоднозначными, это очень хорошая вещь! Я не думаю, что вы хотите, чтобы значение методов менялось в зависимости от контекста:

  • Это добавляет больше сюрпризов, так как вы вносите двусмысленность
  • Ваши пользователи захотят использовать конструкции, которые вы не рассмотрели, например. find("user").where("name").and("email").equals("foo");
  • Трудно сообщить об ошибках: что вы можете сделать с find("user").where("name").not().is().null();?

Давайте также предположим, что я могу охватить большинство правильных английских предложений - в конце концов, сама грамматика ограничена глаголами и конъюнкциями, определенными в SQL.

Нет, вы не можете охватить большинство правильных английских предложений. Другие пробовали раньше, и это очень сложно очень быстро. Это называется пониманием естественного языка, но на самом деле этого никто не пытается: сначала мы пытаемся решить более мелкие проблемы. Для вашей библиотеки у вас есть два варианта:

  • либо вы ограничиваете себя подмножеством английского: это дает вам SQL,
  • или вы пытаетесь осветить «английский» и обнаруживаете, что это невозможно из-за неоднозначности, сложности и разнообразия языка.
Квентин Праде
источник
Спасибо за ваш вклад. Отредактировал мой вопрос, чтобы охватить первый случай, который вы перечислили, и добавил несколько предостережений. Я согласен с вашей позицией в отношении двусмысленности - это суть моего вопроса. Допустимо ли, чтобы языки программирования были амбициозными в четко определенных контекстах?
Фенклифф
если оно неоднозначно, оно не является четко определенным. Если это неоднозначно, есть более чем один потенциальный результат, и что-то должно выбрать один из них. Либо выбор будет четко определен, либо синтаксический анализатор языков будет выбирать случайным образом. Таким образом, неоднозначность в языке программирования является приемлемой, если вы хотите стохастический язык (1 + 1 может быть равен 2, а иногда может быть равен 1 или 3) в отличие от детерминированного (1 + 1 всегда равен 2).
Майкл Полуконис
Вы говорите о его предложении или английском? В большинстве случаев неоднозначность может быть решена с использованием контекста и / или знаний (часть которых является здравым смыслом), что недоступно для компьютера.
Квентин Праде
+1 Хороший улов на чувствительность к контексту его конкретной реализации свободного 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 параллельно! Одно определение абстрактного синтаксиса может поддерживать несколько конкретных синтаксисов. Хотя вы должны помнить, что абстрактный синтаксис - это реальная сделка, конкретный синтаксис также может быть очень полезным.


источник
2

В дополнение к очень хорошим моментам Квентина Праде, я сомневаюсь в предполагаемых преимуществах этого языка.

Предположительно, смысл грамматики, близкой к естественному языку, состоит в том, чтобы сделать ее доступной. Но SQL уже довольно близок к естественному языку. Один из них действительно ближе к английскому, чем другой?

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

select user from table where name = 'foo'

Я не вижу пользы от вашей грамматики с точки зрения интуитивности или читабельности. На самом деле, версия SQL выглядит более читабельной (и ее легче набирать) из-за пробелов.


источник
2

Существует множество плохих, но не идеальных, дизайнерских решений, которые были приняты при рассмотрении этого API.

Во-первых, вопрос полезности - какой цели он служит? Похоже, это создает структуру данных, которая скомпилируется в диалект SQL. Между прочим, грамматика представляется ограниченным набором SQL. Вопрос о том, "какое преимущество это дает по сравнению только с использованием SQL?" становится ключом. Если писать с использованием беглого интерфейса более громоздко, чем просто писать строку с соответствующей интерполяцией, то с помощью этого API нельзя писать.

Английский неоднозначен. Попытка смоделировать свободный интерфейс на английском языке - плохой выбор (лучше использовать латынь ). Когда существует несколько возможных действительных разборов одного и того же набора цепочек вызовов, это приводит к замешательству и удивлению . Ни одна из этих вещей не является хорошей вещью в API.

В SQL больше частей, чем этот API. Соединения (в любой их бесчисленной форме) заметно отсутствуют в наборе примеров. Подзапросы ( foo in (select id from bar)), объединения и группировка - вот некоторые из вещей, которые часто используются. Сложные логические группы, кажется, не присутствуют каким-либо интуитивным образом.

Если кто-то писал с использованием этого API, а затем обнаружил, что API не способен выразить желаемый запрос, значительное время будет потеряно. Неправильно использовать смешанные стили для выполнения запросов в приложении (простые запросы в этом API, сложные в raw sql) - и в конечном итоге будет использоваться более выразительный.

В то время как программирование широко распространено, беглость английского языка - нет. Даже с ограничением языка «SQL как» есть нюансы того, как носитель языка будет читать что-то и кто-то, у кого английский является вторым или третьим языком.

Излишняя избыточность в API ради английского языка. В частности , equal()против equals()делать то же самое. Хотя я не уверен в этом, я полагаю, что is()этот вариант не добавлен ради соответствия английского ближе. Я приветствую всех, кто послушает мои разговоры о избыточности методов в ruby ​​в чате - не делайте ту же ошибку.

Сядьте и напишите исчерпывающий набор примеров запросов, которые вы хотите использовать. Определите, с кем вы будете обращаться со всеми этими примерами не однозначным образом, который будет менее громоздким, чем сами запросы. Если вы не можете, подумайте, стоит ли идти по пути написания API. SQL находится там, где он есть сегодня (он не идеален, но я не нашел ничего лучшего) за десятилетия совершенствования.

RFC 1925 - Двенадцать сетевых истин

(12) В разработке протокола совершенство достигается не тогда, когда нечего добавить, а когда нечего убрать.


источник