Резюме
Перед вами весьма вольный и стилистически неоднородный перевод статьи о модуле для Perl под названием Lingua::Romana::Perligata, который позволяет писать программы на латыни. Автор статьи обещает предоставить ниже правдоподобное обоснование для подобного извращения, а переводчик постарается облечь это в форму, мотивирующую к смежным с темой статьи упражнениям. Также автор предлагает всесторонний обзор синтаксиса и семантики латинизированного Perl и объяснение специальных техник фильтрования и разбора исходных кодов, необходимых для эффективного интерпретирования языка программирования с (почти) вольным порядком слов.
Введение
Относительно других языков (как современных, так и древних), английский имеет относительно слабую лексическую структуру (т. е. обладает аналитическим строем — прим. пер.). Значительная часть грамматической нагрузки в английском предложении лежит на порядке слов. Выражение вроде «The boy gave the dog the food» имеет смысл только в результате соглашения, что подлежащее стоит перед сказуемым, которое стоит перед непрямым дополнением, которое стоит перед прямым дополнением. Изменение порядка — «The food gave the boy the dog'' — меняет смысл. (В русском же языке порядок слов выражает менее значительные грамматические категории, как, например, определенность — прим. пер.)
Большинство языков программирования используют подобный позиционный синтаксис. Оператор $maximum = $next
очень отличается по смыслу от $next = $maximum
. Аналогично, вызов функции push @my_assets, @your_money
— не то же самое, что и push @your_money, @my_assets
.
Вообще говоря, древние натуральные языки (или классические, как о них еще принято говорить — прим. пер.) обладали более богатыми лексическими структурами (такими как склонение по числам и падежам) и поэтому меньше зависели от порядка слов. Например, на латыни предложения „Puer dedit cani escam“ и „Escam dedit puer cani“ оба значат „Мальчик дал собаке еду“. На самом деле, более привычным порядком слов будет обратный польский, с глаголом в конце: „Puer cani escam dedit“.
Подобная гибкость обусловлена тем, что латынь использует флексии (окончания), а не порядок слов, для различения лексических ролей (членов предложения — прим. пер.) Отсутствие суффикса (здесь имеется в виду нулевое окончание — прим. пер.) говорит о том, что мальчик (puer) — подлежащее, окончание -i означает, что собака (cani — собаке) — непрямое дополнение, тогда как окончание -am означает, что пища (escam — пищу) — прямое дополнение.
Чтобы сказать „Еда дала мальчику собаку“, можно написать: „Puero canem esca dedit“. Здесь окончание -o означает, что теперь мальчик — непрямое дополнение, окончание -em — что собака стала прямым дополнением, тогда как -a обозначает, что еда — подлежащее.
Менее позиционный язык программирования
Нет причин, мешающих языкам программирования так же использовать склонение вместо позиции для различения лексических ролей. В Perl эта идея уже нашла некоторое воплощение в необходимости префиксации различных типов: $
для скаляра, @
для массива, &
для подпрограммы, и т. д.
На самом деле, нет никаких причин, почему некоторые встроенные функции, как, например, bless
или блочная форма map
, или даже push
не позволяют обозначить их аргументы в любом порядке, по крайней мере, в случаях, когда префиксы (или их отсутствие) делают их роли однозначными:
my $obj = bless 'Classname', %obj;
@squares = map @numbers {$_**2};
push ('Moe', 'Larry', 'Curly') => @stooges;
Более того, раз имена, которыми их называет функция, однозначны в своих ролях, также нет причин фиксировать и их позиции:
@squares = @numbers map {$_**2};
('Moe', 'Larry', 'Curly') => @stooges push;
Perl уже разрешает небольшую часть этой гибкости в форме модификаторов выражений:
if ($next > $max) { $max = $next }
# ...is the same as...
$max = $next if $next > $max;
Ниже описывается новый модуль Lingua::Romana::Perligata, в котором исследуется альтернативный тип синтаксических связей для Perl, использующий склонение на базе классической латинской грамматики. Склонение дополняет функции стандартных префиксов Perl и поддерживает новую концепцию семантических ролей, которая дает гораздо большую свободу описания функций, операций и их соответствующих аргументов.
Семантические роли
Большая часть богатого разнообразия операторов Perl имеют вариант с присваиванием: +=
для +
, .=
для .
, ||=
для ||
, и т д. Так, около половины операторов Perl меняют один из своих аргументов. Подобно этому, многие из встроенных функций Perl (push
, pop
, open
, и пр.) также меняют один из своих аргументов.
В обоих случаях, операнд или аргумент, подлежащий изменению, определяется положением — это всегда левый операнд или первый аргумент. Более того, этот аргумент всегда явно ссылочный, как если бы он имел прототип с $
или @
.
Таким образом, в Perl операнды и аргументы имеют одну из двух семантических ролей: цель или данные. Цель передается по ссылке и изменяется в ходе выполнения операции или функции. Данные передаются по значению (хоть это значение может быть и ссылкой само по себе) и они контролируют или „питают“ модификацию цели.
В этой модели возможно переписать почти все встроенные функции и операции Perl как процедуры ровно двух аргументов: одной ссылки (цели) и одного списка (данных):
_sysopen( -target=>*FILE, -data=>[$filename,$mode,$perms] );
_push( -target=>@stooges, -data=>['Moe', 'Larry', 'Curly'] );
_pop( -target=>@stack, -data=>[] );
_assign( -target=>$max, -data=>[$nextval] )
if _num_less_than( -target=>undef, -data=>[$max, $nextval] );
_assign( -target=>$now, -data=>[ _time(-target=>undef, -data=>[]) ]);
Обратите внимание, что для многих функций, как один, так и оба элемента могут быть null
.
Перенос модели на латынь
Чтобы перенести эту упрощенную модель Perl на синтаксис, основанный на склонении, необходимо выбрать способ склонения, который различает три компонента каждой функции: имя, цель и данные.
Представьте присваивание списка массиву:
@gunslingers = ( @good, @bad, $Ugly );
В нотации семантических ролей:
_assign( -target=>@gunslingers, -data=>[@good, @bad, $Ugly] );
По-английски это может быть выражено так:
Assign gunslingers goodies and baddies and Mr Ugly.
(Присвой стрелка́м хорошек и плохишей и г-на Урода)
Повелительный глагол „assign“ определяет действие к исполнению. Существительное „gunslingers'' определяет непрямое дополнение (которое соответствует русскому дательному падежу) действия. Другими словами, это получатель эффекта действия — цель. Фраза “goodies and baddies and Mr Ugly» выражает прямое дополнение действия — то, что будет присвоено. Другими словами, данные. Прямое и непрямое дополнения отличаются только порядком, в котором они появляются: непрямой объект сначала.
Английская версия также использует окончание множественного числа в «goodies and baddies», во многом схожее с тем, как Perl использует префикс @
для маркирования множественности используемых объектов.
На латыни та же инструкция могла бы выглядеть примерно так:
Bonos tum malos tum Foedum pugnatoribus da.
(Здесь и далее автор неверно использует tum (тогда) в значении cum (и, с). Ближе к латыни было бы «Bonos cum malos Foedumque» — «Хороших и плохих, да Урода бойцам дай» — прим. пер.)
Читатель может сам разобрать это высказывание по описываемой автором модели.
В отличие от английского, окончания латыни и русского содержат информацию не только о числе, но и о роли. Таким образом, позиция слова не имеет значения. То же предложение могло быть записано:
Pugnatoribus da bonos tum malos tum Foedum.
или
Da bonos tum malos tum Foedum pugnatoribus.
Семантически, все эти варианты (и любые другие перестановки глагола и дополнений) эквивалентны одной и той же модели цели/данных:
_assign( -target=>@gunslingers, -data=>[@good, @bad, $Ugly] );
и, следовательно, эквивалентны выражению на стандартном Perl:
@gunslingers = ( @good, @bad, $Ugly );
Таким образом, можно писать программы на Perl на латыни.
Lingua::Romana::Perligata
Модуль Lingua::Romana::Perligata предоставляет необходимые услуги перевода, чтобы можно было писать Perl-программы в синтаксисе (perligatus), смоделированном на основе древнего lingua Romana. Чтобы отличить их от обычного Perl, этот синтаксис — и любой код в нем — далее будет называться «Perligata».
Переменные
Чтобы упростить мозговзрывающие сложные правила склонения и спряжения, которые управляют словоизменением в латыни, Perligata считает все вводимые пользователем скаляры и массивы существительными среднего рода второго склонения, причем, скаляры единственного числа, а массивы — множественного. Это уменьшает количество суффиксов (имеются в виду окончания — прим. пер.), которые нужно запомнить.
Хэши представляют собой кое-что сложное в Perligata, поскольку в латыни нет очевидного пути отличить эти «множественные» переменные от массивов. Решение в том, чтобы отделить хэши от второго склонения и воспроизвести их в качестве существительных мужского рода четвертого склонения.
Следовательно, тип и роль любых переменных определяются их падежом и числом, как показано в таблице 1.
Когда элементы массивов и хэшей используются непосредственно, в Perl префикс меняется с @
или %
на $
, так что не должно удивлять то, что Perligata также использует различное склонение, чтобы отличить эти случаи.
Операции индексирования, как $array[$elem]
или $hash{$key}
могут быть переведены как «элемент массива» или «ключ хэша». Это подсказывает, что когда массивы и хэши индексированы, их имена должны быть отображены в виде генитива (родительного падежа). Операции многоуровневой индексации ($array[$row][$column]
) значат «столбец ячейки массива», и следовательно, первый индекс тоже должен быть отображен в генитиве.
Таблица 1 подытоживает вышесказанное.
Таблица 1: Переменные в Perligata
Perligata | Число, падеж, склонение | Perl | Роль |
---|---|---|---|
nextum |
Ед. ч., Вин. п., 2-е | $next |
скаляр, данные |
nexta |
Мн. ч., Вин. п., 2-е | @next |
массив, данные |
nextus |
Мн. ч., Вин. п., 4-е | %next |
хэш, данные |
nexto |
Ед. ч., Дат. п., 2-е | $next |
скаляр, цель |
nextis |
Мн. ч., Дат. п., 2-е | @next |
массив, цель |
nextibus |
Мн. ч., Д. п., 4-е | %next |
хэш, цель |
nexti |
Ед. ч., Род. п., 2-е | [$next] |
скаляр, индекс |
nextorum |
Мн. ч., Род. п., 2-е | $next[] |
массив, индекс |
nextuum |
Мн. ч., Род. п., 4-е | $next{} |
хэш, индекс |
Другими словами, скаляры — всегда существительные единственного числа, массивы и хэши — множественного (но разных склонений), а падеж существительного передает роль: аккузатив для данных, датив для цели, генитив для индексируемых переменных.
Переменные, обычно обозначаемые $_
и @_
— особый случай. $_
— это часто значение неявного рассмотрения (нп. при сопоставлении с образцом или в циклах) и поэтому она отображается как «это»: hoc
в роли данных, huic
в роли цели, huius
при индексации.
Аналогично, @_
— список, передаваемый в подпрограмму, так что его можно представить как «эти»: haec
в роли данных, his
в роли цели, horum
при индексации.
Другие пунктуационные переменные берут свои латинские формы из английских эквивалентов (см. приложение A), часто весьма поэтизированных. Например, $/
превращается в ianitorem
, т. е. «gatekeeper».
Цифровые переменные — $1
, $2
, и пр. — выражаются в виде сложных слов: parprimum
(«равный первому»), parsecundum
(«равный второму») и т. д. При индексации они берут соответсвующие формы генитива: parprimi
, parsecundi
, и т. д. Поскольку они не могут быть модифицированы напрямую в качестве цели действия, у них нет форм датива.
my, our, и local
В Perligata модификатор my
выглядит как — неудивительно — притяжательные местоимения первого лица: meo
(в контексте скаляра) и meis
(в контексте списка). Обратите внимание, что модификатор всегда применяется к дативу, и следовательно, сам ставится в этом падеже. Имеем:
meo varo haec da. # my $var = @_;
meis varo haec da. # my ($var) = @_
meis varis haec da. # my @var = @_;
Похожим образом модификатор our
выражается как nostro
или nostris
в зависимости от желаемого контекста.
Модификатор Perl local
— loco
или locis
на Perligata:
loco varo haec da. # local $var = @_;
locis varo haec da. # local ($var) = @_
locis varis haec da. # local @var = @_;
Это частично удача: loco
— не просто слово, от которого происходит само local
, оно также значит «вместо» (как в выражении «in loco parentis»), что гораздо ближе к реальному поведению модификатора local
, временно заменяющего значение символа.
Подпрограммы
Функции, операторы и пользовательские подпрограммы представлены в виде глаголов или, в некоторых ситуациях, отглагольных прилагательных. Здесь изменение слова определяет не только его семантическую роль, но и контекст вызова.
Пользовательские подпрограммы — самая простая группа. Во избежание неоднозначностей все они считаются глаголами третьего спряжения. Таблица 2 иллюстрирует разнообразное использование пользовательской подпрограммы count()
.
Таблица 2: Подпрограммы в Perligata
Perligata | Грамматические признаки | Perl | Роль | Context |
---|---|---|---|---|
countere |
инфинитив | sub count |
определение | -- |
counte |
императив ед. ч. | count() |
вызов | void |
countementum |
результат, ед. ч., вин. п. | count() |
вызов-данные | скаляр |
countementa |
результат, мн. ч., вин. п. | count() |
вызов-данные | список |
countemento |
результат, ед. ч., дат. п. | count() |
вызов-цель | скаляр |
countementis |
результат, мн. ч., дат. п. | count() |
вызов-цель | список |
Использование инфинитива в качестве определения подпрограммы очевидно: accipe
бы сказало Perligata, как «принять», spernere
— как «отклонить». Так что countere
определяет, как считать.
Использование императива (повелительного наклонения — прим. пер.) для контекста void
также прямолинейно: accipe
командует Perligata: «прими!», sperne
— «отклони!», а counte
— «считай!». В каждом случае дается инструкция (и в контексте void
тоже, так что никакого сарказма).
Рахобраться со скалярным и списочным контекстами немного сложнее. Соответствующая латынь все еще должна иметь свойства глагола, так как над объектами производится действие. Но она должна иметь и характеристики существительного, ведь сам результат вызова будет использован как объект (т. е. цель или данные) другим глаголом. К счастью, в латыни есть приличный набор отглагольных существительных — гораздо больше, чем в английском — которые могут принять эту роль.
Поскольку здесь нам интересен результат вызова подпрограммы, лучшим решением будет использование суффикса -ementum
, который определяет (винительный падеж, единственное число) исход действия. Это соответствует результату подпрограммы, вызванному в скалярном контексте и использованному в качестве данных. Для списка данных используется суффикс множественного числа -ementa
, а для целей — формы дательного падежа: -emento
и -ementis
. Обратите внимание, что эти окончания полностью соответствуют окончаниям в таблице 1.
Встроенные функции и операторы
Встроенные операторы и функции могли следовать тем же паттернам, что и подпрограммы. Например, shift
могла быть shifte
в контексте void
, shiftementa
в качестве данных в контексте массива, shiftemento
в виде цели в скалярном контексте и так далее. Однако, в латыни уже есть идеально подходящий глагол с тем же значением, что и shift
: decapitare
— «обезглавливать». К сожалению, этот глагол первого спряжения, а не второго, а следовательно, в императиве дает форму decapita
, которая выглядит как массив в роли данных.
Ортогональность никогда не являлась главным критерием дизайна Perl, так что Perligata жертвует непротиворечивостью в пользу эстетики. Все ключевые слова Perligata — включая имена функций и операторов — являются правильными латинскими словами, какого бы спряжения они не были. Таблица 3 позволяет взглянуть на выборку из них, а в Приложении А содержится полный список.
Таблица 3: Примеры встроенных функций и операторов Perligata
Оператор/функция | Значение | void | скаляр | список |
---|---|---|---|---|
+ |
«прибавить» | adde |
addementum |
addementa |
= |
«дать» | da |
damentum |
damenta |
. |
«соединить» | sere |
serementum |
serementa |
.. |
«перечислить» | conscribe |
conscribementum |
conscribementa |
shift |
«обезглавить» | decapita |
decapitamentum |
decapitamenta |
push |
«положить в стек» | cumula |
cumulamentum |
cumulamenta |
pop |
«извлечь из стека» | decumula |
decumulamentum |
decumulamenta |
grep |
«отсеять» | vanne |
vannementum |
vannementa |
print |
«писать» | scribe |
scribementum |
scribementa |
write |
«подписать» | subscribe |
subscribementum |
subscribementa |
die |
«умереть» | mori |
morimentum |
morimenta |
Обратите внимание, однако, что мы не отрекаемся от непротиворечивости. Обратные дериваты слов в контексте скаляра и списка абсолютно регулярны и не противоречат таковой для пользовательских подпрограмм (Таблица 2)
Некоторые из встроенных функций Perl — pos
, substr
, keys
— могут быть использованы как lvalue. Это значит, что они могут быть целью некоторого другого действия (обычно присваивания). В Perligata подобные случаи записываются дативом единственного числа (поскольку lvalues всегда скалярны). Также обратите внимание, что так как при присвоении lvalue функция также изменяет ее первый аргумент, этот аргумент тоже должен быть целью и потому должен быть написан также в дативе.
Таким образом:
nexto stringum reperimentum da. # $next = pos $string;
nextum stringo reperimento da. # pos $string = $next;
inserto stringum tum unum tum duo excerpementum da.
# $insert = substr($string,1,2);
insertum stringo unum tum duo excerpemento da.
# substr($string,1,2) = $insert;
keyis hashus nominamentum da # @keys = keys %hash;
keya hashibus nominamento da # keys %hash = @keys;
Блоки и управляющие структуры
Натуральные языки обычно используют какие-нибудь скобочные конструкции — как скобки, запятые, или (как здесь) тире — чтобы группировать и разделять набор фраз или предложений.
Подобный механизм был бы очевидным выбором для выделения блоков кода на Perlegata, но есть более эстетически приятное решение. Разделители блоков на Perl ({..}) имеют два желаемых свойства: одни коротки по одной и симметричны попарно. Было признано важным сохранить эти характеристики в Perligata.
В латыни слово sic
имеет значение «так, как здесь». К счастью, если прочитать его задом-наперед, то получится слово cis
, которое среди прочих имеет значение «досюда». Соблазн такой языковой игры был слишком велик, Perligata теперь отделяет блоки выражений двумя этими словами. Например:
In Latin, the word sic has a sense that means ``as follows''. Happily, its contranym, cis, has the meaning (among others) ``to here''. The allure of this kind of wordplay being impossible to resist, Perligata delimits blocks of statements with these two words. For example:
sic # {
loco ianitori. # local $/;
dato fonti perlegementum da. # $data = <DATA>;
cis # }
Управляющие структуры в Perligata выглядят как условные выражения, как они есть в латыни, английском и Perl. И как в этих других языках, они могут стоять до или после блоков кода, которыми управляют. Таблица 4 описывает доступные в Perligata управляющие структуры.
Таблица 4: Управляющие структуры Perligata
Perligata | Perl |
---|---|
si ... fac |
if ... |
nisi ... fac |
unless ... |
dum ... fac |
while ... |
donec ... fac |
until ... |
per (quisque) ... in ... fac |
for(each) ... |
posterus |
next |
ultimus |
last |
reconatus |
redo |
confectus |
continue |
fac
в конце — императив от facere
, «делать». Он служит окончанием управляющего условия.
Выбор между dum
и donec
абсолютно произвольный, поскольку латынь, в отличие от английского, не различает «while» и «until». dum
и donec
оба значат «пока», и латынь опирается на контекст (т. е. семантику), чтобы отличить их. Это непрактично для Perligata, так что donec
всегда считается until
, а dum
— while
. Этот выбор сделан из соображений более краткого слова для обозначения более распространенного цикла.
Выбор confectus
в качестве continue
служит передаче функции управляющей структуры, а не буквальной передаче смысла английского слова. Таким образом, блок continue
определяет, как завершить conficere
итерацию.
Perligata поддерживает только чисто итеративные формы цикла for
/foreach
, но не C-подобный трезчастный синтаксис, потому что:
foreach $var (@list)...
значит «для каждой переменной в списке...», скаляр должен быть в аккузативе (так как он управляется предлогом «for»), и список должен быть в аблативе (выражая включение). К счастью, во втором склонении, формы аблативов совпадают с дативами, так что:
per quisque varum in listis...
Это значит, что не нужно учить дополнительных форм просто для использования в цикле. Все же лучше список (listis
) выглядит как массив Perligata в роли цели, которым он, ясно, и является, так как его содержимое может меняться в цикле.
Дополнительные особенности
Числа
Числовые литералы в Perligata выражаются римскими цифрами — I, II, III, IV,… Однако, первые 10 чисел могут также обозначаться именем: unum
, duo
, tres
, quattuor
, quinque
, sex
, septem
, octo
, novem
, decem
. Нуль, для которого не существует латинского числительного, выглядит как nullum
(«никто»). nihil
«ничто» может быть лучшим переводом, но не склоняется.
Когда числовой литерал используется для индексации, он должен быть порядковым числительным. Первые десять названы primum
, secundum
, tertium
, quartum
, quintum
, sextum
, septimum
, octavum
, nonum
, decimum
.
Порядковые больше десяти передаются римскими цифрами с суффиксом -imum
: XVimum
. По аналогии, нуль получает искуственную форму nullimum
.
При многоуровневой индексации используется также генитив.
Например:
$unimatrix[1][3][9][7];
будет
septimum noni tertii primi unimatrixorum
# seventh of ninth of third of first of unimatrix
Обратите внимание, что порядок генитивов имеет значение и обратен используемуму в Perl.
Числа с плавающей запятой выражаются на Perligata латинскими долями:
unum quartum # 0.25
MMMCXLI Mimum # 3.14
Строки
Классическая латынь не использует пунктуацию для отделения прямой речи. Вместо этого используется глагол «inquit» («сказал»). Следовательно, в Perligata используется специальное служебное слово inquementum
:
Enter tum next tum word inquementum tum biguttam egresso scribe.
Заключение от переводчика
На этом полуслове я оборву детальное описание языка, которое все желающие смогут найти по ссылке внизу.
Гораздо интереснее сделать выводы.
1. При использовании данной библиотеки код становится несколько симпатичней и разнообразней, так и пышет монументальностью.
2. Авторская интерпретация латыни в большинстве случаев не позволяет читать текст программы как латынь. Некоторые любители древнего языка могут даже испытывать баттхерт.
3. Все равно это достаточно интересный опыт приближения языка программирования к естественному, наряду с другими подобными проектами (например, Shakespeare)
4. Многословный синтаксис все-таки не способствует читабельности. До сих пор решить не могу, что понятнее — обычный кишащий спецсимволами Perl или такой вот суррогат.
Автор: sulnedinfind