Атом

Атом в Эрланге это такой своеобразный тип данных, который ничего не выражает кроме самого себя. Смысл его определяется исключительно в контексте выражений, в которых атом располагается, и вообще — логики программы. То же: atom.

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

1> privet. 
privet
2> metka. 
metka
3> 'Privet'. 
'Privet'
4> 'Какая-то метка'. 
'Какая-то метка'
5> metka_777.        
metka_777

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

Атомы (литералы) как правило называют на латинице, причём название — со строчной буквы. Можно использовать символ подчёркивания и цифры, а также знак @. Если надо назвать с заглавной буквы или включить какие-то иные символы (например, кириллические), тогда название атома заключают в одинарные кавычки. То есть название атома будет состоять из нестандартных символов заключённых в одинарные кавычки.

Если использование одинарных кавычек избыточно, то Эрланг их опустит. Так, например, атом 'privet' станет privet, а атом 'pri@vet'pri@vet. В то же время 'pri.vet' так и останется 'pri.vet', потому что в нормальном имени атома точки быть не может.

Атомы чем-то похожи на перечисления (enum) — те тоже мало что сами по себе выражают. Но атомы выражают ещё меньше — только сами себя. Про перечисления можно хотя бы сказать, что есть такой-то enum и у него столько-то вариантов.

Атомы — прекрасная вещь и очень удобная, особенно в функциональном программировании. Часто их используют как метки. Например, кортеж {age, 18} состоит из атома age и целого числа 18. Этот кортеж можно интерпретировать как содержащий возраст (какого-либо человека).

У функций имена, на самом деле, являются атомами. При определении поведения, например, потребуется указать атомы имён тех функций, которые мы желаем иметь в каждом модуле, обладающем данным поведением:

behaviour_info(callbacks) -> [{privet,0}, {poka,0}].

Здесь privet и poka — это атомы, обозначающие имена функций. Самих этих функций может ещё не быть, но потом они должны появиться.

Иногда бывает проще добавить какой-нибудь структуре метку, чем городить в кляузах сложные паттерны и гарды. Такая-то метка (допустим, атом blue) — срабатывает такая-то кляуза, такая-то (red) — другая кляуза.

Пример фильтрации кортежей по атомам-меткам с помощью обработчика списка:

1> L = [ {russia, "Moscow"}, {england, "London"},
    {russia, "Magadan"}, {england, "Liverpool"} ].
[{russia,"Moscow"},
 {england,"London"},
 {russia,"Magadan"},
 {england,"Liverpool"}]
2> [ City || {Country,City} <- L, Country == russia ].
["Moscow","Magadan"]

Атомы не стоит рассматривать исключительно как метки. Недаром атомы назвали атомами. С помощью атомов, например, можно моделировать какие-то химические процессы. Например, кортеж {vodorod, kislorod, vodorod} в нашей программе может служить для обозначения воды. Причём не только для обозначения. Мы можем настроить логику нашей программы так, чтобы при определённых обстоятельствах “молекула” {vodorod, kislorod, vodorod} распадалась на два “иона”: {vodorod, kislorod} и {vodorod}. Эти “ионы” по определённым правилам смогут объединиться с другими — и мы получим возможность генерировать тысячи и миллионы разных веществ. Про какие-то вещества раньше мы, может быть, даже и не догадывались.

Атом занимает в памяти всего одно машинное слово (например, 64 бит). Мы можем дать атому длинное название, но в памяти он будет занимать всё равно те самые 8 байтов. Впрочем, есть ограничение на длину атома: 255 символов. Максимально возможное количество атомов: 1_048_576. В настройках можно изменить это ограничение.

На самом деле, имя терма-атома (которое мы задали в коде) сохраняется в памяти, но только один раз — в специальной таблице. Далее виртуальная машина пользуется ссылками на атом в этой таблице. Эта таблица не подпадает под сборку мусора.

Вот некоторые бифы для работы с атомами:

Часто возникает потребность посылать актору сигнальную информацию, например, для отладочных целей. Вместо строки, которая носит именно сигнальный характер лучше послать атом. Это и экономнее (строка занимает больше места в памяти), и чуть элегантнее: Actor_Pid ! proverka.

Атомы, как и другие термы, можно хранить в таблице ETS или DETS.

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

Если в программе надо задействовать атом, обозначающий название модуля, можно не писать его прямо, а использовать ?MODULE. Препроцессор автоматически поменяет это на название модуля.

Каждая функция (не путать с фунтермами) может быть вызвана по своему атому названия. Например, биф apply/3 может запустить произвольную функцию по атому её названия. apply/3 принимает МФА (модуль, функция, аргументы), и арность рассчитывается автоматически — в зависимости от длины списка аргументов. Так что в зависимости от арности могут быть вызваны разные функции (но с одинаковым атомом названия).

Имя ноды включает знак @, например: komp1@sis. В Эрланге специально предусмотрено, что знак @ может являться частью атома, поэтому имена нод вроде указанного являются не строками, а атомами.


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