Showing posts with label мысли. Show all posts
Showing posts with label мысли. Show all posts

Saturday, December 29, 2007

Как писать парсеры

Обычно парсеры языков программирования пишутся в виде грамматики, которая либо скармливается потом генератору, либо уже представляет собой код с использованием парсер-комбинаторов. К сожалению, если язык сложен, грамматика его тоже непроста. А сложным, надо сказать, становится любой язык, когда в него нужно добавить разумную обработку ошибок и восстановление после таковых, и при этом выдать какое-то достаточно вменяемое синтаксическое дерево на выходе. Ровно это необходимо для хорошей поддержки языка в IDE.

Поэтому в самой знакомой мне IDE парсеры пишутся обычно руками, рекурсивным спуском, скучно, занудно и однообразно (чего стоит один практически идентичный код, раскопированный для каждой бинарной операции). Восстановление после ошибок тогда получается достаточно несложно.

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

Итак, по старинной фортовской привычке мы начинаем с объявления данных кодом. Данные у нас - это поток токенов от лексера, вот они-то и будут кодом. У каждого токена будет свой собственный маленький кодик, вот такого вида:

interface TokenParser {
boolean parseToken(PrattBuilder builder);
}

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

С каждым токеном ассоциируется еще и число, приоритет. Самый главный метод праттбилдера носит скромное название parse, принимает одно число, и идет последовательно, каждый раз для текущего лексерного токена вызывая его токенпарсеры, пока приоритеты токенов строго больше числа-параметра либо пока какой-нибудь токенпарсер не вернет false. Сами токенпарсеры внутри себя могут делать что угодно, сдвигать лексер насколько угодно (в том числе путем вызова билдеровского parse рекурсивно), но не в их власти откатиться раньше токена, для которого их вызвали. Билдер всегда помнит место, в котором вызвали его parse, и умеет создавать узлы дерева, начинающиеся там.

Это была фортовская часть. Теперь к Пратту. Самый частый вариант токенпарсера, DefaultTokenParser, реализован заветами этого товарища, и умеет различать два случая вызова себя и делегировать всю работу одному из двух подпарсеров - соответствующих своих аргументов конструктора. Первый случай, "свежачок", когда токен встретился сразу же в билдеровском parse, слева от него ничего еще нет, у Пратта это зовется nud, у меня пока - PrefixParser (better name needed!!!). Второй случай, когда слева уже что-то есть, и там даже построился узел дерева с определенным типом, у Пратта - led, у меня пока - ProceedingParser (oh name...). Первое используется, когда по токену можно понять, какую конструкцию он начинает (унарная префиксная операция), второй - какую конструкцию он продолжает (инфиксная бинарная операция или много чего еще) или закачивает (унарная постфиксная операция).

У токена нечасто определены оба компонента, самый очевидный пример токена, умеющего и начинать и продолжать - "+" или "-". Если nud или led нужен, но отсутствует, генерируется ошибка. Токен, который мы анализировали, нам уже неинтересен, мы с него все, что хотели, получили, поэтому перед вызовом подпарсеров лексер сдвигается вперед. Оба подпарсера возвращают тип узла, который надо построить от стартового маркера до текущего места. Обычно алгоритм разбора токенпарсера по умолчанию получаются следующим: вызываем nud первого токена, а потом, пока не посинеем, вызываем led у текущих токенов.

Пример простого нуда на псевдоязыке:

unary(IElementType type, int priority) = fun (builder) ->
builder.parse(priority);
return type

И еще проще:

tokenElement(IElementType type) = fun (builder) ->
return type

Пример простого леда (бинарная левоассоциативная операция) почти дословно такой же:

binary(IElementType type, int priority) = fun (leftType, builder) ->
builder.parse(priority);
return type

Постфиксная операция еще проще:

postfix(IElementType type) = fun (leftType, builder) ->
return type

Распарсить простые выражения можно теперь с помощью весьма лаконичного кода:

NUMBER: priority=10, nud=tokenElement(NUMBER_LITERAL)
IDENTIFIER: priority=10, nud=tokenElement(QNAME)

"(": priority=10, nud=fun (builder: PrattBuilder) ->
builder.parse(0);
builder.assertToken(")");
return PARENTHESES

".": priority=9, led=binary(QNAME, 9)
"!": priority = 8, nud=unary(NEGATION, 8)

"+","-": priority=8,
nud=unary(ARITHMETIC_UNARY, 8),
led=binary(ARITHMETIC_BINARY, 6)
"*","/": priority=7, led=binary(ARITHMETIC_BINARY, 7)

Парсер, например, для сокращенного определения класса в Java лучше выражается через просто токенпарсеры:

"public", "static", etc.: priority = -100,
tokenParser = fun (builder) ->
builder.advance();
return true;
"class": priority=-100,
tokenParser = fun (builder) ->
builder.finishPrefix(MODIFIER_LIST);
builder.advance();
builder.assertToken(IDENTIFIER);
if (builder.assertToken(EXTENDS)) {
builder.advance();
builder.parse(9);
}
builder.assertToken("{");
builder.parse(-90);
builder.assertToken("}");
return JAVA_CLASS

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

В данный момент на праттовской основе (только, увы, в синтаксисе Java) в достаточной степени написан парсер для языка шаблонов FreeMarker, и процесс мне нравится. Парсер получается более прямолинейный, проверок условий в нем намного меньше, чем в обычном рекурсивном спуске. Это можно рассматривать как паттерн Visitor, он же полиморфизм, мы вместо делания многочисленных проверок на тип вызываем абстрактный метод у самого типа.

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

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

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

Monday, December 3, 2007

peter-mac:~ peter$

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

Процесс организован следующим образом. Сидит лингвист, смотрит на какой-нибудь неправильный промтовый перевод, размышляет. Придумывает новое правило, которое все разом возьмет и полечит. Идет к программисту, объясняет правило, программист это дело кодит. Далее есть 18М тестовых текстов (или текстовых тестов?), на которых прогоняются старый и новый варианты, и просматриваются отличия (hopefully их немного). Если отличия случились в плохую сторону, лингвист идет думать дальше, иначе изменения принимаются.

Если я все правильно понял, весело быть программистом в ПроМТе. Сидишь, никого не трогаешь, приходят к тебе красивые девушки и рассказывают про правила какого-нибудь экзотического языка. Кругозор, понимаешь, расширяют. Кайф!

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

Расследование показало, что при добавлении какого-нибудь нового языка к системе подсаживается специально обученная группа экспертов, которые долго думают, а потом ее расширяют так, чтобы она нормально угадывала парадигмы и из этого языка. А именно, дописывают еще пару сотен правил. Возникает резонный вопрос - а нафига? Можно же сделать еще более умную систему, которая будет сама на основе примеров выводить те самые правила, которые сейчас в нее забиваются руками! Причем именно для данной задачи (вывод парадигмы) это, по идее, должно быть достаточно просто. И, по счастливому совпадению, это ровно та задача, про которую я туплю уже некоторое время. Так что вот, надо решать.

Tuesday, October 16, 2007

Теморема

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

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

Посему русско-финские языки используют артиклезаменители. Как это устроено в финском, пока не знаю, а в русском эти средства называются туманным словом "контекст". Самый простой вариант, когда слово охарактеризовано как "этот" или "некий", тут все понятно. Только вот часто ли мы так говорим? Лично я - не очень. А если поразмыслить, то получится (по крайней мере, у меня получилось), что степень определенности выражается как раз порядком слов и логическими ударениями. И вот тут мозг начинает медленно распухать от того, что эти два и так не самых легкоопределимых параметра влияют на аж две такие важные вещи.

И тут наступает облегчение. Выясняется, что еще одна пара понятий, которые я уж года два как считал введенными филологами для своих личных гуманитарных целей, оказывается, имеет глубокий смысл и для меня, в этом конкретном контексте. Это тема и рема высказывания. Тема - это субъект, топик высказывания, то, что связывает его с предысторией, информация, уже известная получателю сообщения. Рема - то, зачем нужно высказывание, то, что оно добавляет к знаниям получателя, новая информация, некий факт-предикат про тему. Как правило, в известных мне языках тема предшествует реме. Как правило, рема в них же может выделяться интонационно. В "я еду завтра" тема - "я еду", а рема - "завтра". В "завтра я еду" тема - "завтра я", рема - "еду". "Завтра еду Я!", тема="завтра кто-то едет", рема="не кто-то, а таки я". В "я ЕДУ завтра" тема="я что-то там делаю завтра", а рема="еду, а вовсе даже не иду".

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

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

Воть, такая вот простая мысль. А сколько времени понадобилось для осознания...

Tuesday, September 25, 2007

Гаааваряаат, мы юкси-какси...

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

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

Семантика... Тоже нужна, да. Быть может, она действительно описывается каким-то формальным языком, типа даже Тузовского, только этим текст не исчерпывается. Мы же помним, что для перевода нужно как-то формализовать эффект, который текст производит на читателя, причем даже на разных читателей с разным бэкграундом. А эффект производит не только и не столько семантика, а и какие-то знакомые словосочетания, напоминающие о каком-нибудь Пушкине, или глубокая мораль текста ("всему свое место" в случае сказки про курочку Рябу). Так что при анализе нужно в качестве промежуточного представления иметь даже не язык, описывающий семантику, а некий набор инструкций, которые, будучи примененными к человеку, произведут тот же эффект, что и текст. Инструкции от "вспомнить про Пушкина" до "подумать, что всему свое место" через "создать объект Джизус и сделать так, чтобы он послушал, что некто я (надо бы зарезолвить) не сильно в восторге от происходящего". Сие есть инвариант текста. А потом надо изобресть текст на таргетном языке с тем же эффектом. Короче, ничего нового.

Thursday, July 26, 2007

239 42

Под депрессивную музыку Бадаламенти вспомню, что психолингвистика напомнила мне замечательную фразу, а именно, "Шел дождь и два студента, один в пальто, другой - в аптеку". Фраза занимается примерно тем же, что и "И Василий, и бежит - офигеть!", только в значительно большей степени. Почему-то мне кажется, что если научиться хорошо анализировать ее, то со всем остальным языком сладить уже будет совсем легко. Вот этим анализом и попробую заняться.

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

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

Видимо, тип есть что-то вроде "описание". Довольно непростой тип. Внутри элемента ряда мы видим "один" и "другой", собственно, маркирующими ряд, по которым парсер по идее и поймет, что это ряд, а заодно являющиеся анафорическими ссылками на каждый инстанс студента. Или ряд может иметь формальный вид: "собирательное_название - список_элементов", и в данном случае выглядеть как "два студента - один, другой".

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

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

Итак, что же происходит?
Ряд Б = "два студента: один, другой"
Ряд А = "дождь и" ряд Б
"шел" применяется к ряду А, то есть, "шел дождь" и "шел (Ряд Б)"="(шли два студента): (шел один), (шел другой)"
"в пальто" применяется либо к "другой", либо к "шел (один)", либо к "(шел один)"
"в аптеку" применяется к "шел (другой)"
Результаты применения "шел" мержатся сначала по ряду Б, а потом и по ряду А.
Наконец, программа, подумав, пишет "ржунимагу".

Весь вопрос в том, как же выглядят, собственно, результаты применения. Это может быть выражение на Тузовском семантическом языке, может быть фреймовая модель, может еще что... ХЗ. Видимо, оно должно обладать способностью выразить ровно столько, сколько выражено в исходном предложении на русском языке. There's a catch. В каком-нибудь другом языке можно выразить немного другое количество информации. Представителям другой культуры может быть неважно, что студенты, видимо, мужского пола, но важно, какого цвета дверь в аптеке. Так что либо семантический язык должен быть объединением всех естественных с возможностью сказать все, что возможно сказать на каждом из них, и с возможностью, что еще важнее, выразить все неоднозначности и недоговоренности, проистекающие из синтаксиса и семантики каждого из них (как с "в пальто" в здешнем случае), либо нужно завести по семантическому языку на каждый естественный, и переводить уже между ними. Тут возникает закономерный вопрос, а есть ли необходимость умножать сущности, и нафига вообще нужен такой семантический язык, который выражает то же, что и естественный. Не легче ли воспользоваться готовым естественным. На вопрос на такой есть ответ простой: семантический язык в любом случае во-первых формален, а во вторых в нем, смею надеяться, меньше слов, чем в естественном, и больше дела. Но все равно, конечно, идеальным был бы универсальный семантический язык. Только ведь фиг такой придумаешь. Как сказал кто-то типа Гумбольдта, язык - это наши ограничения в этом мире, некий освещенный круг, в котором мы ориентируемся, и внутри которого находимся. И взглянуть с него со стороны можно, только войдя в другой такой же круг. Здесь же предлагается осветить все круги разом, или охватить их все одним большим кругом, в который они все войдут без остатка. Поэтому бывает интересно посмотреть на разнообразные искусственные языки, коих за последние сто лет насоздавалось немало. К сожалению, пока что я ничего похожего не видел. В основном они стремятся к точности, однозначности, полноте и т.п. (ложбан, ыфкуил) либо наоборот к размытости (токи пона какая-нибудь). А вот чтоб на языке можно было говорить и точно, и размыто - ну разве что евроклоны типа эсперанто. Но это фактически естественные языки, только с сильно упрощенной грамматикой, это такие же небольшие круги, как и все остальные, обычные языки.

Saturday, July 21, 2007

Аспекты теории синтаксиса

Давно пора выразить содержимое головы, а то там места скоро не останется. А так глядишь и для новых мыслей освободится...

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

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

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

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

Кстати, опять же вспоминая Тузова. Видимо, мое любимое слово "не" тоже дистрибутивно. Вырожденный случай, да и дистрибутивно странным образом. Но "он не должен туда ходить" - это ведь "он должен туда (не ходить) ИЛИ он должен (не туда) ходить ИЛИ ... ИЛИ (не он) (не должен) (не туда) (не ходить)", всего 16 вариантов. Может, и не 16, может и меньше, но явно не один. Так что такое вот эквивалентное преобразование точно имеет место.

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

Friday, June 29, 2007

Взрыв мозга. И аккумулятора

Вот написал я в предыдущем посте "сами зависимости тоже могут рассматриваться как знаки" как-то так, не подумав. То есть, подумав, но не сильно. А ведь это концепция. У меня в процессе размышлений над проапгрейженной тузовской проблемой, помнится, была баальшая проблема: как представить слово "красота". Есть глагол "быть красивым", статический глагол состояния с одним аргументом - пациенсом. И с помощью этого глагола можно говорить о том, что икс красив, либо об иксе, который красив. Нексус и юнкция это называется. Или наоборот, не помню уже. А вот как выразить саму концепцию того, что икс участвует в отношении между иксом и "красив"? Например, "красота икса". Во-от. Неясно.

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

А сабж тут ни при чем.

Йа феллосаф

С чего бы это я про Lexical Semantics вспомнил? А вот с чего. Стали тут меня мысли преследовать на тему всяких Сэпиров и Уорфов. Они ведь про что гутарят? Про то, что вот есть язык, а есть реальность (точнее, наивная модель мира в мозгу). И вообще-то еще неясно, кто главнее, кто от кого произошел. Классическая наука утверждает, что язык описывает то, что мы воспринимаем, а гипотеза лингвистической относительности - что от языка зависит, что же именно мы воспринимаем. Истина же наверняка где-то посередине...

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

Интересно, это излечимо?

А Сима тычет дулом вниз, разя его внезапно

Еще Фердинанд де Соссюр, вроде, говорил, что в языке нет ничего, кроме различий. Это я в умной книжке прочитал. А незадолго до того и сам придумал что-то похожее. Ибо когда-то давно писал я что-то про то, как определять семантику просто как множество того, на что это похоже по какому-нибудь признаку. А вот и другой способ: определять семантику слова через антоним. Что просто есть слово и его антоним. И критична для значения в данном контексте только эта пара. Тогда семантикой будет просто "первый член такой-то пары". Например, значение местоимения "он" может быть "Привалов Александр Иванович, мужской, русский и т.д.", может быть "шкаф", а может быть - "не "она"". Воть.

Friday, June 1, 2007

Кот не работает

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

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

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

Интереснее обратное преобразование. Вот видим мы данные, даннее некуда. Таблицу какую-нибудь. Сейчас я попробую показать, что это тоже код. Для начала поймем, совершенно в духе квантовой механики, что сами по себе данные - это ничто, пока не придет наблюдатель и не сделает с ними что-нибудь. Прочитает, например. А может, даже, сделает выводы. Ну дык вот. В результате этого действия как минимум сам наблюдатель изменится. В памяти там останется след или еще что. Может, что-то еще произойдет. Например, данные возьмут и поменяются. Наблюдателем. По итогам наблюдения. Получается, что эти данные мы можем рассматривать как инструкцию алгоритма, приведшую к данному изменению системы. Точнее, ее действие будет эквивалентно результату соответствующего смешанного вычисления этих данных и имеющегося у нас кода. Вот мы и преобразовали данные в код. Другое дело, что нам может казаться неудобным считать все такие данные инструкциями, их получается слишком много и с ними сложно работать. Отсюда мораль - разница между кодом и данными - исключительно субъективна, в удобстве использования.

К чему бы все это? Да вот к размышлениям о том, как система может анализировать саму себя. Например, один уровень абстракции - анализировать другой. Это как человек устроен. Только вот у него далеко не все уровни являются наблюдаемыми, это начинается уже с довольно высокой ступени иерархии. Фиг проконтролируешь работу вегетативной нервной системы какой-нибудь. Ну и вот. Парсер, значит, должен уметь в какой-то момент понимать, что они с текстом только что натворили друг с другом, как преобразовали, и порефлектировать на эту тему. Сделать выводы. Возможно, перепарсить все нах. Грустно...

Гедель и К

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

Friday, May 25, 2007

Мысль

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

Wednesday, May 23, 2007

Первыйнах

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

Умная мысль: метафора - это не какая-то дополнительная фича языка, это его самое сердце. Весь процесс понимания и генерения текста связан с метафорами. Еще б это парсеру сказать...

А еще там такой вдохновенный текст про современные технологии, которые следят за движениями глаз и на их основе что-то делают! Например, подсказывают незнакомые слова в тексте. Или при управлении машиной предпринимают дополнительные меры безопасности. Утверждается, что в будущем все будет так работать. Было бы интересно посмотреть.