Говорит ли ваш код по-русски?

в 16:22, , рубрики: Программирование, программная инженерия, Семантика

Да, это пока не широко распространено. Обработка естественного языка еще недостаточно развита и не интегрирована с разработкой. Также, как нет и удобных способов интегрировать код с поиском или виртуальным помощником (таким как Siri). Голосовые команды имитируют GUI пути (щелчок-открыть-щелчок). Семантический Веб пытается познакомить приложения со смыслом, но все еще не может достигнуть широкой аудитории. Behavior-driven development (BDD) полагается на DSL (предметно-ориентированный язык), который близок к естественному, но этого все еще недостаточно, чтобы научить ваш код говорить.

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

  • который будет адаптирован к естественному языку
  • которому будет легко обучить широкий круг людей
  • который может выступать связующим звеном между естественным языком и компьютерными сущностями
  • который сможет создавать окружение в как можно большем количестве областей программной инженерии

Адаптация

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

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

Недостаток обработки естественного языка заключается в том, что она излишне полагается на правила естественного языка. Эти правила необходимы, чтобы текст был грамматически правильным, но не может помочь пониманию смысла во всех ситуациях. "Юпитер вращается по орбите", "орбита Юпитера", "вращение Юпитера по орбите" весьма близки по смыслу. Различение статической природы Юпитера и динамической природы орбиты весьма условно и зависит от обстоятельств или контекста. Что действительно важно — это (а) что такое "Юпитер", (б) что такое "орбита", (в) чем является их сочетание. Но в тексте обычно нет информации об этом.

Любой подход, который работает со словарями и онтологиями (или классами/объектами и т.п.), обладает другим недостатком. Он выражает отношения предметной области (включая схожесть), но слабо связан с естественным языком. И, соответственно, не выражает некоторых характеристик, которые присущи внешнему миру и познанию, которые выражены в естественном языке. Даже продвинутый подход Семантического Веба имеет ограничения: (а) хотя он утверждает, что может менять классы и принадлежность к ним во время исполнения, но это не может быть полностью сделано, т.к. за основу берутся словари и онтологии, определенных на этапе дизайна, (б) URI необходимы для идентификации, (в) OWL декларации необходимы для смысла, (г) семантические системы рассуждений (reasoners) необходимы для классификации и проверки непротиворечивости.

Поэтому, нам необходим альтернативный подход, который будет:

  • Использовать сбалансированную схожесть (в форме неоднозначного естественного языка, чья неоднозначность будет устраняться насколько это возможно)
  • Иметь компонентную структуру, используя результаты устранения неоднозначностей (явные границы между идентификаторами, явно выраженные отношения)
  • Полагаться на дружественный человеку естественный язык (против машинно дружественных идентификаторов как livesIn, countryID и т.п.)
  • Выборочно использовать словари и онтологии
  • Иметь неограниченную гибкость (способность применять утверждения не только к вещам, к которым они предназначались изначально, но также к похожим на них), присущую естественному языку
  • Иметь неограниченную расширяемость (способность изменять модель, чтобы предоставить более детальное или более сжатое описание в любой момент времени), присущую естественному языку
  • Вовлекать людей для классификации, проверки непротиворечивости, рассуждений, и т.п.

Итого:

Адаптация к естественному языку подразумевает не буквальное его использование, а скорее баланс между его неоднозначностью и точностью, присущей компьютерным подходам.

Обучение

Что может облегчить изучение данного подхода? Во-первых, уже упомянутое использование идентификаторов естественного языка. Во-вторых, устранение неоднозначностей естественного языка. В-третьих, послабление правил. В-четвертых, маркап текста. Почему именно эти пункты?

Идентификаторы естественного языка для носителя языка в большинстве случаев не требуют дополнительного обучения. Устраненные неоднозначности (границы между идентификаторами, явные отношения) просто экономят время для других читателей/потребителей информации (которым не надо делать то же самое в процессе использования). Послабление правил позволяет совместно работать пользователям с разными уровнями знаний. Например, "Юпитер является экземпляром планеты" не столь очевидно для многих пользователей, тогда как "Юпитер — это планета" очевидно для большинства. Маркап текста нужен, т.к. он может быть использован прозрачно (и быть даже невидимым для пользователей, например: Какой диаметр планеты?) и позволяет зафиксировать смысл как только он распознан создателем информации.

Это существенно отличается от того, что уже есть в программировании и других семантических технологиях. Идентификаторы представляют собой не всегда распознаваемые аббревиатуры, естественный язык не обрабатывается или доступен в виде эзотерических результатов, правила очень строгие, нет маркапа текста. Возьмем Семантический Веб для примера. URI могут быть читаться людьми до некоторый степени. Триплеты (подлежащее-сказуемое-дополнение) пытаются имитировать естественный язык, но получаемый результат сложно прочитать человеку. Тяжеловесные стандарты полны множеством правил. Альтернативой, предположительно, являются Notation3 и Turtle, которые вроде бы должны легко читаться людьми. Но и здесь мы опять видим "дружественные человеку" URI и названия вроде dc:title (что может выглядеть читаемым в данном примере, но будет dc_fr12:ttl в другом). Микроформаты предлагают немного иной подход, который может использоваться только в HTML, и который, в конце концов, является разновидностью предметно-ориентированного языка (DSL). DSL хотя и рассматривается как многообещающее направление, но имеет свои достоинства и недостатки, где последние могут быть объяснены одной фразой: необходимость знания нового языка. Во всех случаях мы видим, что обучение является очень важным фактором, которым мы просто не можем пренебречь.

Итого:

Восходящий, постепенный подход с ослабленными правилами позволяет стартовать буквально с нуля, как это возможно во многих языках программирования. Можно начать работать со словами естественного языка и отношениями, которые могут быть ограничены буквально двумя-тремя самыми важными. Это минимизирует необходимость в сложной, дорогой и недостаточно надежной (с точки зрения понимания текста) обработке естественного языка. Распознавание идентификаторов и основных отношений — более простая задача, чем распознавание существительных-глаголов-прилагательных-наречий или триплетов (подлежащее-сказуемое-дополнение) или определений классов/полей/методов. Это может быть сделано и использовано без дополнительного анализа как людьми, так и алгоритмами.

Связующее звено

Что делает функция getBallVolume(diameter)? Классическая интерпретация заключается в соотношении выхода и входа в виде описании как "Возвращает объем шара в соответствии с диаметром". В терминах естественного языка это может быть выражено как вопрос "Какой объем шара?" или "Какой объем шара с диаметром равным X?" или в виде предложения, упомянутого выше. Чтобы связать функцию с естественным языком нам нужно связать вход и выход функции с, соответственно, входом и выходом в естественном языке. Как это сделать? Вопрос может быть разделен на значимые идентификаторы и отношения: "Какой {является} объем {чего} шара?", где (1) выход функции соотносится с "какой" или неизвестным, (2) вход функции соотносится с "объем {чего} шара" или "шар {имеет} объем", (3) отношения "{является}" и "{чего}"/"{имеется}" связывают идентификаторы входа и выхода. Теперь мы можем написать тест при помощи библиотеки meaningful.js:

meaningful.register({
    func: getBallVolume,
    question: 'Какой {_} {является} объем {чего} шара',
    input: [ { name: 'диаметр' } ]
});
expect(meaningful.query('Какой {_} {является} объем {чего} шара {имеет} диаметр {имеет значение} 2')).
    toEqual([ 4.1887902047863905 ]);

Что здесь происходит? (1) функция getBallVolume регистрируется, чтобы отвечать на вопрос "Какой объем шара?" с параметром диаметр, (2) задается вопрос "Какой объем шара с диаметром 2?" (который примерно эквивалентен упомянутому в коде), (3) проверяется ожидаемый результат. Как это работает? Внутри, входящий вопрос и вопрос, связанный с функцией, сравниваются и если они похожи (т.е. похожи их соответствующие компоненты), тогда результат может быть найден: (а) "Какой {}" похож на "Какой {}" во втором вопросе, (б) "объем {чего} шара" присутствует в обоих вопросах, (в) в функции register() "диаметр" не включен в вопрос, но присутствует как параметр входа, поэтому его можно поставить в соответствие с "диаметром" во втором вопросе, (г) "диаметр {имеет значение} 2" применяется как вход и вызывается getBallVolume(2), (д) результат функции возвращается как ответ на вопрос естественного языка.

Немного более сложный пример (регистрация функции getBallVolume здесь подразумевается):

function getPlanet(planetName) {
    return data[planetName]; // возвращает данные из внешнего источника
}

meaningful.register({
    func: getPlanet,
    // падежи не поддерживаются - вот где необходима обработка естественного языка
    question: 'Какой {_} {является} диаметр {чего} планета', 
    input: [{
        name: 'планета',
        // ключ имени планеты в нижнем регистре
        func: function(planetName) { return planetName ? planetName.toLowerCase() : undefined; } 
    }],
    output: function(result) { return result.diameter; } // возвращается только одно поле JSON-а
});

// добавляем правила похожести
meaningful.build([ 'Юпитер {является экземпляром} планета', 'планета {является} шар' ]); 
expect(meaningful.query('Какой {_} {является} объем {чего} Юпитер')).toEqual([ 1530597322872155.8 ]);

Как это работает? (а) "Юпитер {является экземпляром} планета", поэтому мы можем рассматривать вопрос "Какой объем Юпитера?" как "Какой объем планеты?", (б) "планета {является} шар", поэтому мы можем рассматривать этот вопрос как "Какой объем шара?", (в) "диаметр {чего} Юпитер" может быть извлечен из атрибута диаметра объекта планеты, возвращаемого из вызова getPlanet("Юпитер"), (г) вызывается getBallVolume() со значением диаметра Юпитера.

В Java (так же как в других мультипарадигмальных языках программирования) такие примеры могут выглядеть даже более элегантно:

@Meaning шар
class BallLike {

    @Meaning диаметр
    int diameter; // на английском имя поля можно использовать буквально

    @Meaning объем
    // каждое поле/метод по умолчанию соответствует
    // вопросу "Какое значение {_} {является} поле {чего} класса?"
    double getVolume(); 

}

Подобный подход проще чем тот, который предлагается программными интерфейсами виртуальных помощников: Siri, Google Assistant, или Cortana. Только тот факт, что здесь мы видим несколько видов программных интерфейсов может обескураживать больше, чем возможные плюсы от интеграции с разговаривающим виртуальным помощником. Из этих программных интерфейсов одна технология является наиболее схожей с данным подходом: структурный маркап данных, но он недостаточно читабелен.

То, что предлагает Семантический Веб не является кратким и похоже на обработку XML. Запросы в Семантическом Вебе в виде SPARQL ограничены, как и любой вид SQL-подобного языка. Вопросы естественного языка — это нечто большее, чем только выбор полей/свойств. Они затрагивают также пространство-время, причины-следствия и некоторые другие важные аспекты реальности и познания, которые требуют специального обращения. Теоретически, мы можем использовать вопрос "Какое место" вместо "Где", "Какая дата" вместо "Когда", или "Какая причина" вместо "Почему", но постоянные вопросы с "Какой/какая/какое" будут звучать не очень привычно в естественном языке.

Данный подход также может быть сравнен с тем, что делают поисковые системы. Которые могут извлечь диаметр планеты, но результат не может быть переиспользован непосредственно. объём планеты же просто не работает. Также, мы не можем извлечь другие еще более специфичные данные. Данный же подход может помочь получать ответы на эти и многие другие вопросы, а также делает сам код субъектом поиска на естественном языке.

Итого:

Ненавязчивый подход не принуждает ваши данные быть совместимыми с тяжеловесными стандартными или специальными структурами данных (как триплеты) и специальными хранилищами данных (как триплетсторы). Напротив, он может быть адаптирован под ваши данные. Он является скорее разновидностью интерфейса, который может быть применен и к новым, и к старым (уже практически не поддерживаемым) данным. Т.е., вместо строительства Гигантского Глобального Графа данных, к чему Семантический Веб, похоже, стремится, данный подход предлагает создать "Веб вопросов и ответов", который будет являться частично дискретным (т.к. отдельные идентификаторы и отношения дискретны) и частично непрерывным (т.к. и идентификаторы, и отношения могут быть приблизительно схожими с другими).

Окружение

Как мы можем видеть, маркап может быть преобразован как в естественный язык (и использоваться поисковиками или виртуальными помощниками), так и в вызовы программного интерфейса (что образует своего рода интерфейс естественного языка). Маркап превращает текст в компонентную структуру, где каждый элемент может быть заменен похожим. Поэтому, в большинстве случаев, преобразование в естественный язык может быть довольно простым или, по крайней мере, упрощенным: "Какой {является} диаметр {чего} планеты?" может прямо соответствовать вопросу "Какой диаметр планеты?" и быть схожим с "Какой диаметр астрономического объекта?". Что же касается интерфейса естественного языка (NLI), вначале идея использовать "Какой {является} объем {чего} Юпитера" вместо jupiter.getVolume() или getBallVolume(jupiter.diameter) кажется избыточной. Но никто и не говорит, что NLI вызовы должны относиться ко всем строчкам кода. Это может применяться только к тем частям кода, которые являются значимыми для высокоуровневого дизайна. Более того, у данного интерфейса имеются определенные плюсы: (а) спецификация, совместимая с естественным языком, (б) мы не работаем с конкретными вызовами программного интерфейса (что уменьшает необходимость углубленного изучения конкретного API), (в) названия классов/методов/функций/параметров более явные, (г) комментарии могут быть превращены в более осмысленный маркап, который может быть переиспользован, и т.п. Также, NLI может быть простейшим способом (даже по сравнению с командной строкой) разработки интерфейса для небольших приложений и устройств (например, в Интернете вещей) или в среде со многими языками программирования.

Вследствие двойственной совместимости с естественным языком и кодом, маркап также может быть использован в других областях программной инженерии: требования, тесты, конфигурация, пользовательский интерфейс, документация, и т.п. Например, строка из требований "Приложение должно предоставлять диаметр планет" может быть размечена и соотнесена с вызовами функций, тестами или частями пользовательского интерфейса.

Маркап может открыть еще одну область исследований: причина-следствие. Современные приложения делают робкие шаги в этом направлении и обычно как-то пытаются объяснить причины ошибок или неожиданного поведения. Но эта практика не распространяется на многие другие сферы: например, какие опции влияют на определенную функциональность, и т.п. Чтобы это работало еще более эффективно, подобные объяснения должны быть доступны для переиспользования. Т.е., если какая-то функциональность недоступна, то приложение может раскрыть цепочку причин-следствий-альтернатив с прямым доступом к тем местам пользовательского интерфейса или к опциям, которые пользователь может сразу изменить.

Хотя behavior-driven development двигается в похожем направлении, но есть весьма важные отличия. DSL, схожий с естественным языком, может выглядеть неплохо, но, в конце концов, он не может быть переиспользован без инструментов, которые распознают этот DSL. С другой стороны, почему мы должны ограничиваться только тестами или дизайном? Мы взаимодействуем с естественным языком и высокоуровневой архитектурой предметной области на всех этапах программной инженерии.

Итого:

Данный подход применим не только к коду, но и к текстовым документам, пользовательскому интерфейсу, функциональности, конфигурации, сервисам и веб-страницам. Это открывает новые горизонты взаимодействия. Так, веб-страница может быть использована как своего рода функции вместе с алгоритмическими функциями, и, наоборот, функция из программного кода может быть использована, как своего рода веб-страница в поиске.

Заключение

Наибольшим вызовом для Семантического Веба является ответ на вопрос, почему он необходим сообществу, также как RDF, триплеты, триплетсторы, автоматические рассуждения (reasoning), и т.п. Приложения связывали данные в течении многих лет перед Семантическим Вебом. Архитекторы определяли предметную область при помощи различных инструментов (включая онтологии) задолго до него. Совершенно непонятно могут ли перевесить преимущества использования тяжеловесных стандартов, схожих с XML/UML/SQL стоимость миграции и затрат на обучение. Возможно, что именно поэтому Семантического Веба нет в стандартных библиотеках широко распространенных языках программирования и нет планов по включению. Семантический Веб позиционирует себя как "Веб данных", который позволяет интеллектуальным агентам справляться с разнородной информацией. Как подразумевается, люди будут получать информацию из "черного ящика", который будет рассуждать (reason) за них. Стандарты Семантического Веба далеки от того, чтобы люди могли их читать (как естественный язык) и похоже это никого не беспокоит. Не видно и дискуссий о применимости и удобстве использования семантики. А зачем? Интеллектуальные агенты же все сделают сами. Просто адаптируйтесь к Семантик Вебу. Вдохновляюще, не правда ли?

Напротив, предлагаемый подход легковесен и может быть реализован при помощи встроенных особенностей JavaScript и underscore.js (не говоря уже о мультипарадигмальных языках). Итоговый прототип содержит всего лишь около 2 тысяч строчек кода. Легковесность ведет к упрощенному синтаксическому разбору, простым структурам данных, и не очень сложным цепочкам рассуждений (reasoning). Является ли это чрезмерным упрощением Семантического Веба? Возможно, также как ваша локальная база данных может являться чрезмерным упрощением Больших Данных, но ведь у обоих вариантов просто различная сфера применимости.

Может ли данный подход ответить на вызовы Семантического Веба? Нужно помнить, что они вызваны, в первую очередь, потенциальной громадностью (vastness), неоднозначностью (vagueness), неопределенностью (uncertainty), противоречивостью (inconsistency) и подверженностью ошибкам (fallibility) познания. Человечество живет с этими вызовами уже многие годы, но они действительно представляют собой угрозу для негибких, ограниченных, узкоспециализированных, категоричных алгоритмов.

Любая информация является потенциально громадной, неоднозначной, неопределенной, противоречивой, подверженной ошибкам. Взять хотя бы тот диаметр Юпитера. Его значение выглядит простым и определенным только пока мы ограничиваем себя и представляем это как "раз и навсегда застывшую" истину. Но это не так. Оно может быть очень сложным, если мы хотим подсчитать его очень точно, что может вовлечь множество подзадач. Оно может быть неоднозначным, т.к. меняется во времени, может быть вычислено различными методами и с различной точностью. Оно может быть неопределенным, если мы вспомним все допущения, например, что Юпитер является идеальным шаром. Значение в метрической системе может быть противоречивым (в отсутствие средств перевода) с иными единицами длины. Все, что вы должны знать о подверженности ошибкам вы можете найти в поисковом запросе "диаметр Юпитера": источники предоставляют с дюжину различных значений.

В реальном мире, мы всё это понимаем. Мы осознаем, что у нас просто может не хватать ресурсов, чтобы рассматривать каждое значение учитывая эти вызовы. Но это может быть действительно опасным, если мы рассматриваем черный ящик, которому мы абсолютно доверяем. Мы не можем себе такое позволить. Нам нужна постоянная обратная связь и коррекция (как вариант, в диалоге между человеком и алгоритмом). Мы должны рассматривать эти вызовы скорее, как особенности или рутину, а не проблемы.

  • Громадность (vastness) поощряет любопытство и планирование. Слишком большая задача всегда может быть разделена на подзадачи, которые могут быть делегированы.

  • Неоднозначность (vagueness) ведет к гибкости. Мы используем довольно неоднозначный естественный язык, где каждое слово достаточно точно только при определенных условиях. Мир меняется каждый миг и все, что мы "поймали в реальности" часто приходит в негодность уже в следующий момент. Но и неоднозначные характеристики, такие как "юный" могут рассказать даже больше о человеке, чем его очень точный возраст. Определение качеств — это всегда результат процесса оценки, обобщения, определенных рассуждений. Это экономит время, которая нужно потратить другим людям на такую же квалификацию (хотя и есть вероятность, что результат не является допустимым для наших требований).

  • Неопределенность (uncertainty) несет в себе альтернативы и заставляет нас управлять рисками. Это совершенно нормально, когда у нас на выходе получается несколько результатов. Ведь иногда выбором нужного результата должен заниматься человек, который может или должен принимать решение.

  • Противоречивость (inconsistency) мотивирует многогранность и многофункциональность. Ведь непротиворечивость, в большинстве случаев, вытекает из множества способов упорядочивания окружающего мира. Это может быть сделано весьма различными путями и, чтобы исключить некоторые из них, мы должны иметь полную картину. Но как раз то ее у нас может и не быть во многих ситуациях.

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

Все эти пункты подразумевают ту или иную степень вовлеченности человека. Ведь как раз люди и могут проинтерпретировать является ли результат достаточно громадным, неоднозначным, неопределенным, противоречивым или ошибочным. Это может быть допустимым, но может быть пересмотрено, это может изменить направление поиска, это может потребовать ручных изменений в данных или коде (что является видом рассуждений), и т.п. Люди умеют обращаться с подобной информацией, поэтому это должно поддерживаться ими (сообществом пользователей и инженеров вместе с многочисленными библиотеками, приложениями и устройствами). И такая поддержка возможна только, если код сможет разговаривать на естественном языке. И это как раз то, что данный подход может сделать реальностью.

Это перевод статьи. Ссылки ведут на англоязычные ресурсы, т.к. аналогичные на русском языке не содержат всей необходимой информации. Также примеры кода приведены на русском в иллюстративных целях, работающие тесты пока используют английский язык.

Автор: meaningful

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js