2 Введение в lexd: морфология
2.1 Техническое введение
В данном разделе мы обсуждаем синтаксис программы lexd (Swanson и Howell 2021). Данная программа работает в связке
- с бесплатным програмным обеспечением с открытым исходным кодом Helsinki Finite-State Tookit
hfst(Lindén и др. 2011); - аналогичным инструментом от Apertium
lttoolbox(Ortiz Rojas, Forcada, и Ramı́rez Sánchez 2005).
Это консольная программа, работающая на юниксоподобных системах. Чтобы избежать сложностей на начальных этапах курса, мы решили вначале познакомиться с синтаксисом lexd и попробовать описывать разные языковые явления, не затрудняя всех установкой и запуском у себя на компьютере. В связи с этим мы предлагаем выучить следующие четыре команды, которые будут работать на операционных системах Linux, основанных на Debian/Ubuntu, и в Google Colab:
- скачиваем инструкции для установки
lexdиhfstи дальнейшей работы с ними, записанные в простом текстовом файле, которые можно прочитать, если открыть ссылку из команды. Командаmakeзапускает установку. Для того, чтобы это работало в Google Colab нужно перед командой нужно поставить восклицательный знак:!curl .... Знак доллара означает, что дальше следует команда командной строки, не надо его никуда копировать.
```{shell}
$ curl -s https://raw.githubusercontent.com/agricolamz/2025_morphological_transducers/refs/heads/main/task_tests/Makefile -o Makefile; make
```- дальше мы ожидаем, что вы создадите в коллабе или у себя на компьютере (если у вас Linux), файл с названием
task.lexd. В Google Colab для этого достаточно вставить первой строкой кодового блока%%writefile task.lexd. Вот пример такого файла:
```{lexd}
PATTERNS
VerbRoot VerbInfl
LEXICON VerbRoot
sing<v>:sing
walk<v>:walk
dance<v>:dance
LEXICON VerbInfl
<pres>:
<pres><3><sg>:s
```- После того, как вы установили нужные программы и создали файл, можно посмотреть формы и разборы, которые генерируются трансдьюсером. Это можно сделать следующей командой (не забудьте поставить восклицательный знак перед
makeв Google Colab):
```{shell}
$ make forms
sing<v><pres>:sing
sing<v><pres><3><sg>:sings
walk<v><pres>:walk
walk<v><pres><3><sg>:walks
dance<v><pres>:dance
dance<v><pres><3><sg>:dances
```- Кроме того можно посмотреть анализ/генерацию конкретных форм (не забудьте поставить восклицательный знак перед
makeв Google Colab):
```{shell}
$ make analysis FORM="sings"
hfst-lookup: Warning: It is not possible to perform fast lookups with OpenFST, std arc, tropical semiring format automata.
Using HFST basic transducer format and performing slow lookups
> sings sing<v><pres><3><sg> 0,000000
``````{shell}
$ make generation FORM="walk<v><pres><3><sg>"
hfst-lookup: Warning: It is not possible to perform fast lookups with OpenFST, std arc, tropical semiring format automata.
Using HFST basic transducer format and performing slow lookups
> walk<v><pres><3><sg> walks 0,000000
```- В ходе курса мы будем разбирать разные лингвистические задачи. У каждой задачи есть номер и автоматический тест, который его проверяет. Чтобы запустить автоматическую проверку, следует ввести команду, где первое число – номер раздела, а второе число – номер задачи. Например, для того, чтобы проверить, работает ли проверка задания, попробуйте запустить следующую команду:
```{shell}
$ make test_02_01
```- Чтобы окончательно посмотреть все варианты, попробуйте изменить последнюю строчку файла
task.lexdна<pres><3><sg>:Sи снова перезапустить команду:
```{shell}
$ make test_02_01
```2.2 Программа lexd
У программы lexd есть подробный туториал, так что данный раздел во многом опирается на него. Давайте подробнее рассмотрим lexd файл, который мы видели в прошлом разделе:
```{lexd}
1PATTERNS
VerbRoot VerbInfl
2LEXICON VerbRoot
3sing<v>:sing
walk<v>:walk
dance<v>:dance
4LEXICON VerbInfl
5<pres>:
6<pres><3><sg>:s
```- 1
-
Обязательный раздел
PATTERNS, в котором каждая строка сообщает, как могут соединяться элементы из разных групп лексикона. - 2
-
Группа лексикона, которая состоит из слова
LEXICONи имени, под которым данная группа появляется в разделеPATTERNS - 3
- Наполнение группы. Первым идет разбор, а потом после двоеточия языковой материал. Морфологические теги принято записывать в треугольных скобках.
- 4
-
Вторая группа
LEXICONи ее имя. - 5
- Пример нулевой морфемы.
- 6
- Пример морфемы с несколькими морфологическими тегами.
Отметим, что можно создавать свои именнованные подразделы PATTERN, которые потом можно использовать в разделе PATTERNS, например:
```{lexd}
PATTERNS
VerbStem Tense PersonNumber
1PATTERN VerbStem
VerbRoot
VerbRoot Causative
LEXICON VerbRoot
...
LEXICON Causative
...
LEXICON Tense
...
LEXICON PersonNumber
...
```- 1
-
Именованный раздел
PATTERN, который используется потом в разделеPATTERNS.
Таким образом, в каждом файле lexd должен быть раздел PATTERNS, содержащий в себе переменные, которые могут быть заданы либо в разделе PATTERN, либо в разделе LEXICON, либо их анонимные варианты (см. раздел Раздел 2.2.2). Также разные разделы можно переименовывать при помощи группы ALIAS (см. мануал). Комментарии можно оформлять при помощи хеша #.
2.2.1 Операторы
Квантификация напоминает регулярные выражения:
?— ноль или один раз*— ноль и более раз 1+— один и более раз
```{lexd}
PATTERNS
Root Negation?
LEXICON Root
...
LEXICON Negation
...
``````{lexd}
PATTERNS
Root
Root Negation
LEXICON Root
...
LEXICON Negation
...
```|— оператор или (можно с пробелами вокруг)
```{lexd}
PATTERNS
Root PastInflection|PresentInflection
LEXICON Root
...
LEXICON PastInflection
...
LEXICON PresentInflection
...
``````{lexd}
PATTERNS
Root PastInflection
Root PresentInflection
LEXICON Root
...
LEXICON PastInflection
...
LEXICON PresentInflection
...
```- Кроме того есть операторы, названные в матералах
lexdситом,>и<:
```{lexd}
PATTERNS
VerbRoot > TAM > CLITICS
LEXICON Root
...
LEXICON TAM
...
LEXICON CLITICS
...
``````{lexd}
PATTERNS
VerbRoot
VerbRoot TAM
VerbRoot TAM CLITICS
LEXICON Root
...
LEXICON TAM
...
LEXICON CLITICS
...
```2.2.2 Анонимные разделы
Некоторые фрагменты аннотации можно вставлять прямо в раздел PATTERNS. Для этого используются квадртные скобки.
```{lexd}
PATTERNS
NounStem [<n>:] NounNumber
LEXICON NounStem
sock
ninja
LEXICON NounNumber
<sg>:
<pl>:s
``````{lexd}
PATTERNS
NounStem NounNumber
LEXICON NounStem
sock<n>:sock
ninja<n>:ninja
LEXICON NounNumber
<sg>:
<pl>:s
``````{lexd}
PATTERNS
NounStem NounTag NounNumber
1LEXICON NounTag
<n>:
LEXICON NounStem
sock
ninja
LEXICON NounNumber
<sg>:
<pl>:s
```- 1
-
Новый раздел
LEXICON.
В мануале это трюк назван Anonymous LEXICON, видимо, потому что предполагается, что мы таким образом избегаем создания дополнительного раздела LEXICON (см. развернутый пример 2).
По аналогии с анонимным разделом LEXICON есть анонимный раздел PATTERN. Для этого используются круглые скобки.
```{lexd}
PATTERNS
(VerbRoot Causative?) | AuxRoot Tense PersonNumber
LEXICON VerbRoot
...
LEXICON Causative
...
LEXICON AuxRoot
...
LEXICON Tense
...
LEXICON PersonNumber
...
``````{lexd}
PATTERNS
VerbStem | AuxRoot Tense PersonNumber
1PATTERN VerbStem
VerbRoot Causative?
LEXICON VerbRoot
...
LEXICON Causative
...
LEXICON AuxRoot
...
LEXICON Tense
...
LEXICON PersonNumber
...
```- 1
-
Новый раздел
PATTERN.
2.2.3 Теги
На содержимое разделов LEXICON можно вешать теги. Это может быть полезно, например, для моделирования словоизменительных классов. Рассмотрим пример из русского языка (славянские, индоевропейские):
```{lexd}
PATTERNS
NounStem[hard] Inflection[hard]
NounStem[soft] Inflection[soft]
LEXICON NounStem
мама:мам[hard]
папа:пап[hard]
няня:нян[soft]
Таня:Тан[soft]
LEXICON Inflection
<nom><sg>:а[hard]
<nom><sg>:я[soft]
<gen><sg>:ы[hard]
<gen><sg>:и[soft]
```То же самое можно записать при помощи одного тега, используя операцию отмены тега:
```{lexd}
PATTERNS
NounStem[hard] Inflection[hard]
NounStem[-hard] Inflection[-hard]
LEXICON NounStem
мама:мам[hard]
папа:пап[hard]
няня:нян
буря:бур
LEXICON Inflection
<nom><sg>:а[hard]
<nom><sg>:я
<gen><sg>:ы[hard]
<gen><sg>:и
```Однако в русском языке можно найти аффиксы, которые присоединяются к обоим типам основ, в таком случае, придется усложнить наше описание:
```{lexd}
PATTERNS
NounStem[hard] Inflection[hard]
NounStem[soft] Inflection[soft]
NounStem Inflection[-hard,-soft]
LEXICON NounStem
мама:мам[hard]
папа:пап[hard]
няня:нян[soft]
Таня:Тан[soft]
LEXICON Inflection
<nom><sg>:а[hard]
<nom><sg>:я[soft]
<gen><sg>:ы[hard]
<gen><sg>:и[soft]
<pos>:ин
```Авторы lexd добавили возможность взаимодействия тегов, чтобы не надо было писать одно и то же.
(A B)[x] = (A[x] B) | (A B[x])
```{lexd}
PATTERNS
(A B)[x]
LEXICON A
aaa[x]
bbb
LEXICON B
AAA[x]
BBB
```aaaAAA
aaaBBB
bbbAAA
(A B)[-x] = A[-x] B[-x]
```{lexd}
PATTERNS
(A B)[-x]
LEXICON A
aaa[x]
bbb
LEXICON B
AAA[x]
BBB
```bbbBBB
A[|[x,y]] = A[x] | A[y]
```{lexd}
PATTERNS
A[|[x,y]]
LEXICON A
aaa[x]
bbb[y]
ccc
```aaa
bbb
A[^[x,y]] = A[x,-y] | A[-x,y]
```{lexd}
PATTERNS
A[^[x,y]]
LEXICON A
aaa[x]
bbb[y]
ccc[z]
ddd[x,y]
eee[x,z]
fff[y,z]
ggg
```aaa
eee
bbb
fff
^ — очень полезный оператор, который позволяет смоделировать согласование по признакам
(A B)[^[x,y]] = (A[x,-y] B[x,-y]) | (A[-x,y] B[-x, y]):
```{lexd}
PATTERNS
(A B)[^[x,y]]
LEXICON A
aaa[x]
bbb[y]
ccc
LEXICON B
AAA[x]
BBB[y]
CCC
```aaaAAA
aaaCCC
cccAAA
cccBBB
bbbCCC
bbbBBB
Это позволяет смоделировать наш русский пример одной строчкой:
```{lexd}
PATTERNS
(NounStem Inflection)[^[hard,soft]]
LEXICON NounStem
мама:мам[hard]
папа:пап[hard]
няня:нян[soft]
Таня:Тан[soft]
LEXICON Inflection
<nom><sg>:а[hard]
<nom><sg>:я[soft]
<gen><sg>:ы[hard]
<gen><sg>:и[soft]
<pos>:ин
``````{lexd}
PATTERNS
NounStem[hard] Inflection[hard]
NounStem[soft] Inflection[soft]
NounStem Inflection[-hard,-soft]
LEXICON NounStem
мама:мам[hard]
папа:пап[hard]
няня:нян[soft]
Таня:Тан[soft]
LEXICON Inflection
<nom><sg>:а[hard]
<nom><sg>:я[soft]
<gen><sg>:ы[hard]
<gen><sg>:и[soft]
<pos>:ин
```2.2.4 Моделирование разрывных морфем: инфиксы, редупликация, семитские корни
В разеделе PATTERNS можно перечислять разные стороны единиц (или входное и выходное значение), записанных в LEXICON2. Это позволяет:
- опускать либо глоссы, либо морфемы (полезно для моделирования редупликации);
- иметь разный порядок глосс и морфем (но зачем?).
Вот пример моделирования дистрибутивных числительных (т. е. числительных со значением ‘по Х’) в зиловском андийском (андийские, нахско-дагестанские):
```{lexd}
PATTERNS
Numerals NumeralMarker
NumeralReduplication :Numerals Numerals NumeralMarker NumeralDistributiveMarker
LEXICON Numerals
чIе # числительное 2
лъоб # числительное 3
ойлIи # числительное 6
LEXICON NumeralMarker
<num>:гу
LEXICON NumeralDistributiveMarker
<distr>:
LEXICON NumeralReduplication
<rdp>:
```чIе<num>:чIегу
лъоб<num>:лъобгу
ойлIи<num>:ойлIигу
<rdp>чIе<num><distr>:чIечIегу
<rdp>лъоб<num><distr>:лъоблъобгу
<rdp>ойлIи<num><distr>:ойлIиойлIигу
Кроме того для моделирования разрывных морфем, вводится номер в круглых скобках, а элементы морфемы перечисляются через пробел. Вот пример, из иврита (симитские, афразийские):
```{lexd}
PATTERNS
C(1) V(1) C(2) :V(2) C(3) V(2):
LEXICON C(3)
sh m r # соблюдать, защищать
y sh v # садиться
LEXICON V(2)
:a <v><p3><sg>:a
:o <v><pprs>:e
```shmr<v><p3><sg>:shamar
shmr<v><pprs>:shomer
yshb<v><p3><sg>:yashab
yshb<v><pprs>:yosheb
2.2.5 Регулярные выражения
В разделе LEXICON допускаются регулярные выражения, для этого их нужно обромлять косыми чертами /:
- группировка при помощи скобок
() - квантификация при помощи
?,*, и+. Объект квантификации должен быть обрамлен круглыми скобками. - логическое ‘или’
| - группы символов при помощи квадратных скобок
[] - промежутки символов [a-z]
```{lexd}
PATTERNS
SomeLexicon
LEXICON SomeLexicon
/x(y|zz)?[n-p]/
```xyn
xyo
xyp
xzzn
xzzo
xzzp
xn
xo
xp
Это позволяет добавлять разбор неизвестных единиц в lexd. Важно отметить, что добавление некоторых типов регулярных выражение делает циклический трансдьюсер, поэтому результат такого трансдьюссера можно посмотреть только при помощи команд make analysis FORM="..." или make generation FORM="...".
```{lexd}
PATTERNS
Stem Affix
LEXICON Stem
стол
дом
/([а-я])*/
LEXICON Affix
<nom><sg>:
<gen><sg>:а
<acc><sg>:
<dat><sg>:у
<ins><sg>:ом
<loc><sg>:е
``````{shell}
$ make analysis FORM="комом"
hfst-lookup: Warning: It is not possible to perform fast lookups with OpenFST, std arc, tropical semiring format automata.
Using HFST basic transducer format and performing slow lookups
> комом ком<ins><sg> 0,000000
комом комом<acc><sg> 0,000000
комом комом<nom><sg> 0,000000
```