Терм

Терм — отдельный, правильно сформированный (валидный) кусок данных того или иного типа, результат вычисления того или иного выражения. То же: term, термин.

Слово “терм” имеет концептуальное, сквозное значение: вот у нас есть кусок данных, называемый термом, мы его можем прогнать через все стандартные механизмы, без всяких исключений. Если говорят, что, например, обработчик списка принимает любой терм, значит всё без исключения можно прогнать через обработчик списка: числа, пиды, фунтермы и др.

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

В Эрланге можно создавать весьма “мохнатые” структуры данных. Например, список кортежей атомов, чередующихся с бинарниками и фунтермами. Если структура правильно сформирована, значит, она — терм.

В стандартной библиотеке можно найти, например, такие функции для работы с термами:

Чтобы хорошо понять работу той или иной функции или, скажем, оператора case, надо точно выяснить, какого рода термы они принимают и отдают. Грубо говоря, можно натолкнуться (или самому написать) функцию, которая будет принимать список, но состоящий только из чётного количества элементов. Если будет нечётное количество элементов, это вызовет ошибку. Другой пример: функция будет прекрасно работать со всеми целыми числами, но не с нулём. При разной арности функции могут принимать термы разного типа. Например, spawn/1 и spawn/2 принимают фунтерм, а spawn/3 и spawn/4 — атом функции.

Значение терма можно привязать к переменной. Если привяжем терм к анонимной переменной, то ошибки не будет, но значение окажется не привязанным.

Как вывести в оболочке терм полностью

Иногда можно столкнуться с такой проблемой. Мы желаем вывести содержимое длинного списка или какого-то замысловатого терма, а оболочка обрезает слишком длинную, как ей кажется, часть. В таких случаях можно воспользоваться командой оболочки rp():

1> L = lists:seq(1,50). 
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,
 23,24,25,26,27,28,29|...]
2> L.
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,
 23,24,25,26,27,28,29|...]
3> rp(L).
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,
 23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,
 43,44,45,46,47,48,49,50]
ok

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

Сравнение термов

Отличительной особенность Эрланга является то, что любой терм можно сравнить с любым термом: число со строкой, атом со ссылкой, фунтерм с пидом и т.д. Результат будет закономерным, то есть с каждым разом мы будем получать один и тот же результат сравнения. Закономерность эта, конечно, натянута, но зато мы имеем очень удобный инструмент для сортировки.

Любое число всегда будет меньше любого атома. Любой атом всегда будет меньше любой ссылки. Полностью эта схема выглядит так:

number < atom < reference < fun < port < pid < tuple < map < list < binary

Внутри этих категорий результат сравнения тоже всегда закономерен.

Всего для сравнения термов есть восемь операторов:


© Алексей Карманов, 2024.