Сергей Холодилов ([info]fat_crocodile) wrote,

КомбинАторный Синтаксический анализ - I

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

!!! Все умные мысли в этом и следующих нескольких постах принадлежат [info]aa5779, который вёл семинар. Я только обработал и изложил. !!!

"КомбинАторный" от слова "комбинатор", ударение на А. Помните Остапа Бендера? Но он тут почти не при чём.

1. Комбинаторы

Первое, что нужно понять - что такое комбинаторы. Это очень просто. Это такие штуки, которые можно просто комбинировать друг с другом.

1.1. Примеры

Несколько штучек:
  • Электрический. Провода, выключатели, лампочки. С соблюдением несложных правил они хорошо и просто сопрягаются друг с другом (правило в данном случае одно: что угодно можно соединить с проводом; а, например, выключатель с выключателем напрямую - нельзя), образуют единую систему, которая как-то функционирует. Чтобы она функционировала со смыслом, нужны отдельные усилия, но это не важно.

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

  • Пластилин... Нет, пластилин не подходит. Почему - объясню ниже.

  • Лингвистический-словообразовательный-I. Ну, понятно, да? Корни, приставки, суффиксы. Приставки в начале, суффиксы в конце... Как обычно, главное - состыковать, о том чтобы был смысл нужно думать отдельно. И не здесь :)

  • Лингвистический-словообразовательный-II. Движемся ближе к телу. Комбинатором будет не суффикс-приставка-корень, а действие. Действие типа <добавить в конец суффикс 'ок'> или <добавить в начало приставку 'пере'>. Этим комбинаторам нужны какие-то входы - чтобы было к чему добавлять. Комбинатору <корень 'дуб'> ничего не нужно. Для построения слов с несколькими корнями нужно несколько комбинаторов слияния типа <соединить первое и второе, вставить между ними 'о'>. Несложно построить из таких комбинаторов какое-нибудь слово, например передубомедвежок. Корень 'дуб', корень 'медвеж', объединяем, добавляем в начало приставку, а в конец суффикс. Видите, как полезно?

Ну и наконец математический пример. Математические функции - вполне себе комбинаторы. Например, введя функции:

mul(x, y) = x*y
add(x, y) = x + y
neg(x) = -x
inv(x) = 1/x

можно записать выражение a/b + c*d - e/(h - g) в виде
add(
    add(
        mul(a, inv(b)),
        mul(c, d)
    ),
    neg(
        mul(e, 
            inv(add(h, neg(g)))
        )
    )
)
Я, конечно, не решусь сказать, что это проще читать :) Но это точно проще вычислять, потому что это выражение синтаксически единообразно. Нам не нужно думать о приоритете операторов (сначала умножить, потом сложить), не нужно думать о количестве параметров, не нужно знать, что делают операции. Нужно только вызвать их.

1.2. Обобщения

Почему не подходит пластилин и почему всё, что подходит комбинировать просто? Просто - потому что комбинаторы просты и всегда одинаковы. Кирпич - всегда кирпич, синус - всегда синус. В отличие от йогуртов, все кирпичи полезны в одинаковой степени (при одинаковом способе употребления) - потому что модель проще гораздо: бац - и готов. Внутреннее устройство комбинатора совершенно не важно при его использовании. Важно, что есть стандартный способ соединения. Важно, сколько у него дырок и сколько пупырышков (входных и выходных параметров). И важно, что в какое место комбинатор не сунь, его поведение (значение на выходе) зависит только от значений входных параметров, и больше ни о чего. И, конечно, мы не можем снаружи никак изменить это поведение. Только очень могучий шаман может изменить значение синуса в указанной точке.

Итого, требования к простоте:
  • семантическая независимость от контекста.

  • стандартный интерфейс ("синтаксическая независимость")

Дальше, несложно заметить, что комбинируя комбинаторы, мы опять получаем комбинаторы (корабли лавировали, лавировали, да не вылавировали :)). Ну действительно:
  • Сколько элементов конструктора вместе не соединяй, результат имеет стандартные пупырышки, стандартные дырочки для них, ведёт себя просто, постоянно - значит комбинатор.

  • Для лингвистических нужно сначала ввести синтаксис записи. Ну, пусть так: <аргумент>.<комбинатор>. Например: 'абв'.<добавить в конец суффикс ок>.<добавить в начало приставку пере>. В результате, конечно переабвок. Ну, в общем, понятно, что часть <добавить в конец суффикс ок>.<добавить в начало приставку пере> это вполне себе комбинатор, ни чем принципиально не отличающийся от своих составных частей.

  • С функциями этот фокус вообще в школе проходят :)

1.3. Комбинаторы высших порядков

Движемся от материальных примеров ко всё более абстрактным. Рассмотрим нашу недлинную эволюцию:
  • В первых примерах комбинаторы были чем-то, что можно пощупать: лампочки, кирпичики, суффиксы.

  • Следующий этап - комбинаторы, являющиеся вычислительными процессами: <добавить в конец суффикс 'ок'>, вычислить синус. Примерно с этого этапа можно было начинать жаловаться что "началась жосткая математика".

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

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

  • А вот создание одной программы другими это ежедневная программистская реальность. Программы, создающие программы это компиляторы. Ну, ещё есть всякие генераторы скриптов и т.п. С приниманием на вход сложнее, хотя можно вспомнить плагины, dll и прочий COM. Но это уже немного натянутый пример.

  • Возвращаясь к электрической цепи. Розетка это универсальное гнездо, к которому подключаются комбинаторы типа пылесоса и холодильника, преобразующие ток во что-то полезное. Это можно рассматривать так, что розетка - комбинатор, принимающий на вход ток и "полезный комбинатор". Её задача - правильно вызвать комбинатор, переданный ей в параметре. Хороший пример, проблема только в "можно рассматривать": это не самая естественная модель для такой ситуации :)

  • Люди - не совсем комбинаторы. Но.. Рожающие женщины :) Они, очевидно, порождают. А мужики? А они, гм, принимают комбинатор на вход.. и возвращают новый комбинатор, отличающийся от старого свойством "беременна" :) [натяжка, натяжка, даже передёрг я бы сказал.. но пусть будет :)]

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

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

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

Вот примерно так работают комбинаторы высшего порядка.

1.4. Ненужное добавление

В рамках семинара - вам это не нужно знать :) Но вообще, комбинаторы это одна из моделей вычислений. Скорее всего, Тьюринг-полная. На эту тему есть большая теория, которой я, конечно, не знаю. Есть несколько стандартных комбинаторов (Y, K, I, кажется), на которых вся строится... Но в данном случае это всё правда не важно :)

Продолжение:

2. Контекстно-свободные языки и грамматики
3. Собственно комбинаторный синтаксический анализ
4. Оптимизация
Tags: ликбез, программинг

  • Post a new comment

    Error

    Your reply will be screened

  • 24 comments

[info]dtim

April 14 2008, 19:18:14 UTC 4 years ago

Круто. Снимаю шляпу. Спасибо.

[info]fat_crocodile

April 14 2008, 19:28:27 UTC 4 years ago

Пожалуйста :) Будет ещё две части. Примерно на том же уровне доступности :)

Но, вообще-то это не мне спасибо. Это я на семинаре для побывал, причём я слушал, а не читал. Добавил в пост ссылку на докладчика (в самом начале).

[info]dtim

April 14 2008, 19:33:22 UTC 4 years ago

Здорово. И докладчику спасибо тоже :).
Жалею, что такие примеры мне в голову не приходили, когда читал функциональщину на втором курсе :).

[info]arsegorov

April 14 2008, 22:44:28 UTC 4 years ago

Напоминает интерфейсы

[info]fat_crocodile

April 14 2008, 22:58:22 UTC 4 years ago

Применительно к математике такого термина не встречал. Откуда это?

[info]arsegorov

April 14 2008, 23:40:07 UTC 4 years ago

Из программирования

[info]fat_crocodile

April 14 2008, 23:54:37 UTC 4 years ago

Ну, это не спортивно :) Из программирования и я могу.

Интерфейсы не совсем подходят. Они не гарантируют отсутствия побочных эффектов. Соблюдение интерфейса это только второе требование - некоторая синтаксическая свобода. Комбинатор же ещё и делает всегда одно и то же. В этом их слабость, но в этом и сила.

[info]arsegorov

April 15 2008, 00:06:27 UTC 4 years ago

Тогда я не совсем понял пример с конструктором: две детальки можно соединить многими способами

[info]fat_crocodile

April 15 2008, 06:06:39 UTC 4 years ago

Ну да, но деталька же от этого не меняется...

синус и косинус можно соединить как минимум двумя способами: sin(cos(x)) и cos(sin(x))
Да, блин, главное забыл :) Соединение комбинаторов это [вроде бы всегда] тоже комбинатор. Т.е. не зависит от контекста и вставляется куда нужно.

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

[info]dtim

April 15 2008, 06:46:31 UTC 4 years ago

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

[info]aa5779

April 15 2008, 08:44:56 UTC 4 years ago

это как раз необязательно...

...то есть это безусловно правильное определение, если у нас базовым понятием является \-исчисление. А если мы исходим из системы SKI, то комбинатор -- это, очевидно, то что можно получить из базовых комбинаторов...

[info]dtim

April 15 2008, 08:56:36 UTC 4 years ago

Re: это как раз необязательно...

Согласен. Но тогда надо определять, что такое базовый комбинатор :). Это, конечно, нетрудно - аксиоматически. Но, судя по всему, речь все-таки пойдет о комбинаторах как о функциях в языке программирования, а не о SKI, а тут, ИМХО, удобнее говорить о связывании переменных. Тем более, что о контексте речь уже зашла.

Anonymous

April 15 2008, 11:06:56 UTC 4 years ago

Re: это как раз необязательно...

Ну да. Но если мы акцентируем внимание на комбинаторах как строительных блоках, (а мы именно это и делаем) -- то естественнее IMHO представление о комбинаторах как о том, что можно построить из других комбинаторов, начиная с базовых.
Впрочем, все это сводится к известной проблеме point-free style, если вы понимаете о чем я -- некоторые считают, что это очень круто, улучшает читаемость и maintainability, другие считают прямо противоположное...

[info]dtim

April 15 2008, 11:13:50 UTC 4 years ago

Re: это как раз необязательно...

Ну лучше всего, думаю, уметь посмотреть и с той, и с другой стороны :).

Пожалуй, относительно строительных блоков "аксиоматический" взгляд действительно несколько удобнее. Про point-free ("pointless" :)) style знаю, да. Причем как раз при использовании комбинаторых библиотек (вроде тех же парсеров) он как раз, мне кажется, очень полезен.

[info]aa5779

April 15 2008, 08:38:21 UTC 4 years ago

дааааа

Присоединяюсь к сниманию шляпы. Примеры что надо.
(Для тех кто не в танке -- у меня в выступлении их не было, а наоборот
было много формул)

[info]fat_crocodile

April 16 2008, 03:11:47 UTC 4 years ago

Re: дааааа

Спасибо :)

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

А что-то такое необходимо, т.к. в сухом виде информация не усваивается.

Во время лекции живой докладчик "разбавляет" сухую информацию естественным образом, это происходит незаметно и естественно, по другим каналам восприятия, поэтому вживую обычно хватает одного примера. У меня под рукой только один канал, поэтому получается гораздо более многословно и избыточно, приходится одно и тоже объяснять несколько раз. Именно поэтому за лекцию можно успеть рассказать/услышать больше, чем самому прочитать за те же 45 минут. И поэтому же книжки гораздо толще конспектов, хотя информации в них столько же.

Так что это просто разные жанры.
А писать понятные тексты я умею, это да.

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

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

[info]aa5779

April 15 2008, 08:41:17 UTC 4 years ago

единственная проблема...

...которую я вижу в подобных метафорах -- то что они не охватывают комбинаторы высшего порядка (к которым относятся и parsing combinators).
Впрочем, с электрической цепью я могу себе что-то в этом роде представить -- если предположит что по проводам можно передавать не только ток, но и лампочки :)

[info]fat_crocodile

April 16 2008, 02:54:31 UTC 4 years ago

Re: единственная проблема...

Ага, точно, забыл про них. Теперь есть :)

С лампочками и проводами тяжело - по типам не подходят.

[info]elada

May 18 2008, 10:12:49 UTC 4 years ago

А можно я весь текст перевешу на сайт семинара, с указание авторства разумеется?
Сейчас там только ссылки на Ваши посты: http://mathlingvo.ru/nlpseminar/archive/s_9

[info]fat_crocodile

May 18 2008, 10:33:00 UTC 4 years ago

А может не надо? :)

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

Обещаю, что когда вдруг доведу до ума - сообщу Вам, тогда размещайте, пока пусть ссылки будут.

[info]elada

May 18 2008, 10:43:47 UTC 4 years ago

Желание автора - закон. Но когда вдруг, мы будем очень рады :)

[info]fat_crocodile

May 18 2008, 10:44:43 UTC 4 years ago

Договорились.

[info]jns_sveta

April 28 2009, 07:41:25 UTC 3 years ago

Здорово написано))) Спасибо))) Даже я поняла)))

[info]fat_crocodile

April 29 2009, 11:07:32 UTC 3 years ago

Пожалуйста :)
Create an Account
Forgot your login or password?
Facebook Twitter More login options
English • Español • Deutsch • Русский…