SQL-волшебник
0,0
рейтинг
27 сентября 2013 в 22:56

Разработка → Erlang для самых маленьких. Глава 1: Типы данных, переменные, списки и кортежи tutorial


Добрый день, дорогие хабражители.

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



Что бы начать работать с Erlang, в терминале выполните:
    $ sudo apt-get install erlang
    $ erl

Запустится интерпретатор, в нем и надо выполнять примеры из статьи.
В Erlang в конце выражения ставится точка, а не точка с запятой, как в большинстве языков. Комментарии начинаются со знака % и продолжаются до конца строки.

Итак, давайте начнем.

Числа


Erlang поддерживает два типа численных переменных: целочисленные и числа с плавающей точкой. Над числами можно производить такие математические операции как сложение, вычитание, умножение и деление:
	1> 7 + 3.
	10
	2> 12 - 4.
	8
	3> 5 * 2.
	10
	4> 12 / 6
	2.0
	5> 7 div 3.
	2
	6> 7 rem 3.
	1

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

Так же Erlang позволяет производить несколько операций за раз. Математические операции подчиняются стандартным правилам приоритета. Поэтому результатом выражения 2 + 3 * 4. будет 14, потому что умножение имеет более высокий приоритет, чем сложение. Для того, что бы явно задать порядок вычислений нужно использовать скобки:
	1> (2 + 3) * 4.
	20
	2> -(10 + 3).
	-13

К тому же, вы не обязаны ограничиваться только десятичной системой счисления. Вы можете использовать числа с любым основанием от 2 до 36. Для этого число необходимо указывать в виде Base#Value.
	1> 2#11011.
	27
	2> 10#1198.
	1198
	3> 16#A04F.
	41295
	4> 36#1TA.
	2350

Но и это еще не все. В Erlang вы можете использовать числа с разными основаниями в одном выражении:
	1> 2#11011 + 36#1TA.
	2377
	2> 10#1198 - 16#A04F.
	-39841
	3> 3#201 * 4#321.
	1083


Атомы


Атомы — это аналог именованных констант из других языков, причем значение атома в точности соответсвует его названию. Грубо говоря, атом — это строка, которую нельзя изменить.

Атомы должны начинаться со строчной буквы и могут содержать в себе строчные и заглавные буквы, цифры, знак подчеркивания(_) и собаку(@). Так же атом можно заключить в одинарные кавычки и тогда он может включать в себя любые символы. Ну и конечно же атом не может совпадать с зарезервированным словом. Поэтому названия атомов after and andalso band begin bnot bor bsl bsr bxor case catch cond div end fun if let not of or orelse query receive rem try when xor недопустимы.
	1> atom.
	atom
	2> otherAtom.
	otherAtom
	3> atom_with_underscore.
	atom_with_underscore
	4> one@more@atom.
	one@more@atom
	5> 'Atom with whitespace'.
	'Atom with whitespace'
	6> ' Atom with special charactes #^&?'.
	' Atom with special charactes #^&?'
	7> Atom.
	* 1: variable 'Atom' is unbound
	8> after.
	* 1: syntax error before: 'after'


Логические типы данных и операторы сравнения


Булевы типы данных в Erlang — это два зарезервированных атома: true и false.
С этим связан один любопытный и неочевидный факт. Но об этом чуть позже.

В языке реализованы все основные логические операции такие как «и»(and), «или»(or), «исключающее или»(xor) и «отрицание»(not).
	1> true or false.
	true
	2> true and false.
	false
	3> true xor false.
	true
	4> not false.
	true
	5> (not (true xor true)) or (false and true).
	true

Операторы and и or всегда вычисляют значения выражений с обеих сторон от себя. Поэтому при выполнении кода (1 > 2) or (3 < 4). будут найдены значения обоих выражений, хотя после вычисления правого выражения результат уже известен. Если вы хотите избежать этого, используйте операторы andalso и orelse.

Для сравнения значений между собой используются операторы «равно»(==), «соответсвенно равно»(=:=), «соответственно неравно»(=/=), «неравно»(/=), «меньше»(<), «меньше или равно»(=<), «больше»(>) и «больше или равно»(>=).
	1> 2 == 2.0.
	true
	2> 2 =:= 2.0.
	false
	3> 3 /= 3.0.
	false
	4> 3 =/= 3.0.
	true
	5> 5 > 5.
	false
	6> 5 =< 5.
	true

Если вы раньше программировали на других языках, то, скорее всего, привыкли, что в них true равно 1, а false равно 0. В Erlang это правило не работает:
	1> true == 1.
	false
	2> false == 0.
	false
	3> false > 19. %% !!!
	true

Обратили внимание на третью строку? Странно, неправда ли? А все дело в том, что Erlang позволяет сравнивать значения разных типов и при сравнении руководствуется следующим правилом: число(number) < атом(atom) < ссылка(reference) < функция(fun) < порт(port) < процесс(pid) < кортеж(tuple) < список(list) < битовая строка(bit string). Выше мы говорили, что true и false — атомы, а из приведенного выражения видно, что атомы «больше» чисел. Поэтому и получается, что false > 19..

Переменные


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

Имя переменной должно начинаться с заглавной буквы или знака подчеркивания(_). Имя переменной может состоять из одного только знака подчеркивания. Но переменная с таким именем не запоминает значение. Такие переменные используются для сопоставления с образцом (об этом смотрите далее).
	1> Variable = 10 - 7.
	3
	2> OtherVariable = 3 * 4.
	12
	3> _result = Variable + OtherVariable.
	15
	4> _result.
	15
	5> Variable = 5.
	** exception error: no match of right hand side value 5


Кортежи


Иногда группу переменных, которые каким-либо образом связаны между собой, удобнее хранить вместе. Для этого Erlang предоставляет такую конструкцию, как кортеж. Кортеж имеет следующий вид: {Value1, Value2, ..., ValueN} и может содержать любое количество переменных.

Давайте рассмотрим на примере, как можно использовать кортежи. Довольно заезженный пример: нам необходимо хранить информацию о точке на координатной плоскости (координаты X и Y). Мы могли бы завести две отдельных переменных и хранить координаты в них, но ведь проще хранить их вместе.
	1> MyPoint = {2,5}.
	{2,5}

Как указано выше, размер кортежа не ограничивается двумя значениями. Так же кортеж может содержать значения разных типов, в том числе и другие кортежи.
	1> MyTuple = {1,myAtom,true,{1,false}}.
	{1,myAtom,true,{1,false}}


Сопоставление с образцом


Для извлечения значений из кортежа (и не только для этого) используется сопоставление с образцом. Для начала давайте еще раз разберем, как работатет оператор сопоставления(=). Он берет значения справа и сопоставляет их с переменными, находящимися слева. Грубо говоря, это то же самое присваивание из императивных языков с одним лишь отличием: сопоставить возможно только несвязанные переменные, т.е. те у которых еще нет значения.

Сопоставление с образцом — это, когда вместо одиночной переменной указывается «шаблон», который должен соотвествовать данным. И если данные соответствуют шаблону, то переменные из этого шаблона будут сопоставлены с соответствующими значениями.
	1> {X,Y} = {1,2}.
	{1,2}
	2> X.
	1
	3> Y.
	2
	4> Z = {Y,X}.
	{2,1}
	5> {A,B,C} = {myAtom,true,Z}.
	{myAtom,true,{2,1}}
	6> A.
	myAtom
	7> B.
	true
	8> C.
	{2,1}

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

Не всегда нам нужны все данные. К примеру, нам может понадобиться только второе значение тройки (тройка — это кортеж из трех значений). Что бы не «плодить» бесполезные сущности, мы можем использовать cпециальную переменную, о которой говорили раньше: _. Тем самым мы укажем, что в этом месте шаблона должно быть некое значение, но нам оно не нужно. Причем в шаблоне может быть несколько таких переменных. Удобно, не правда ли?
	1> {_,X,_} = {1,2,3}.
	{1,2,3}
	2> X.
	2


Списки


Список — это аналог массивов из императивных языков. Список имеет следующий вид: [Value1, Value2, ..., ValueN]. Элементы списка не обязательно должны быть одного типа. Один список может содержать числа, атомы, кортежы, другие списки и т.д.
	1> [1,2,true,atom,{5,4},[true,false]].
	[1,2,true,atom,{5,4},[true,false]].

При работе со списками в Erlang есть один странный момент:
	1> [100,101,102,103].
	"defg"

Erlang вывел список в виде строки. Не стоит волноваться. Это касается только его отображения в терминале. На самом деле наш список все так же содержит числа. Такое поведение связанно с особенностями происхождения языка. Изначально в Erlang не было строк. И для работы с ними использовали списки, которые хранили номера символов. К счастью, язык развивается и сегодня у нас есть возможность нормально работать со строками.

Списки можно складывать (++) и вычитать друг из друга(--). Помните, что эти операторы тоже правоассоциативны.
	1> [1,2,3,4,5] ++ [6,7].
	[1,2,3,4,5,6,7]
	2> [1,2,3,4,5] -- [2,3].
	[1,4,5]
	3> [1,2,3] ++ [].
	[1,2,3]
	4> [1,2,3,4,5] -- [1,2,3] -- [3].
	[3,4,5]
	5> [1,2,3] ++ [4,5,6] -- [4,5].
	[1,2,3,6]

Так же списки можно сравнивать между собой. Для этого используются стандартные операторы сравнения. Сначала сравниваются головы списков. Если они равны, то сравниваются головы хвостов и т.д. Списки сравниваются по первым различным элементам. В приведенном ниже примере первый список больше потому, что первый элемент, который отличается от соответствующего элемента второго списка больше (4 > 1).
	1> [1,2,3,4,0] > [1,2,3,1,1000,2000,6589].
	true

Списки делятся на две части: голову(head) и хвост(tail). Голова — это первый элемент списка, а хвост — все остальное. У хвоста, в свою очередь, тоже есть голова и хвост. При сопоставлении с образцом используется оператор |, что бы указать, где проходит граница между головой и хвостом.
	1> [Head|Tail] = [1,2,3,4,5].
	[1,2,3,4,5]
	2> Head.
	1
	3> Tail.
	[2,3,4,5]
	4> [Second|_] = Tail.
	[2,3,4,5]
	5> Second.
	2


Генератор списков


Конечно же мы не будем постоянно задавать списки вручную. Это довольно утомительно и совсем не интересно. К счастью, создатели языка придерживаются такого же мнения и поэтому Erlang имеет инструмент для автоматического создания списков. Принцип его работы лучше всего рассматривать на примере. Давайте для начала напишем код, который автоматически составит список, который будет содержать в себе числа от 1 до 10, умноженные на 3.
	1> [X*3 || X <- [1,2,3,4,5,6,7,8,9,10]].
	[3,6,9,12,15,18,21,24,27,30]

Наше выражение имеет вид [Expr || Item <- SourceList]. Erlang поочередно берет каждый элемент из SourceList и подставляет его в выражение Expr, на место переменной Item. Результат этого выражения добавляется в результирующий список. Достаточно просто, не правда ли?

Но генератор в том виде, в котором он есть сейчас практически бесполезен. Усложним задачу. Сделаем так, что бы генератор работал только с четными числами из исходного списка, которые больше 5.
	1> [X*3 || X <- [1,2,3,4,5,6,7,8,9,10], X rem 2 =:= 0, X > 5].
	[18,24,30]

Теперь наш генератор имеет вид [Expr || Item <- SourceList, Condition1, Condition2, ..., Condition2]. Работает он в точности, как и первый вариант, но теперь Erlang проверяет, чтобы каждый элемент исходного списка подходил под указанные условия. Если элемент не подходит хотя бы под одно — он пропускается.

Но и это еще не все. Исходных списков может быть несколько. Давайте для примера напишем генератор, который вернет все возможные комбинации четных чисел от 1 до 5 и нечетных чисел от 6 до 10. Пусть комбинация будет представлена кортежем из двух элементов — парой.
	1> [{X,Y} || X <- [1,2,3,4,5], Y <- [6,7,8,9,10], X rem 2 =:= 0, Y rem 2 =:= 1].
	[{2,7},{2,9},{4,7},{4,9}]

В самом общем случае генератор имеет вид [Expr || Item1 <- SourceList1, Item2 <- SourceList2, ..., ItemN <- SourceListN, Condition1, Condition2, ..., ConditionN]. В этом случае Erlang вернет декартово произведение исходных списков (точнее их элементов, которые подойдут под условия).

Генераторы списков — очень мощный инструмент, предоставляемый нам языком. И мы будем очень часто использовать его.

Заключение


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

В следующей статье мы рассмотрим как использовать существующие и создавать новые функции. А так же работу с модулями.

Спасибо за то, что читали. Хорошего вам кода.
@HaruAtari
карма
37,7
рейтинг 0,0
SQL-волшебник
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

Самое читаемое Разработка

Комментарии (64)

  • 0
    Про сопоставление как всегда кратко :( Хотя самое интересное же…

    Можно ли написать шаблон условие что все входящие значения разные, т.е. например есть для триплетов вида {1,2,3} или {atom1, atom2, atom3} выпонялось, а для триплетов вида {1,1,1} или {atom1, atom2, atom1} нет?

    Можно ли написать шаблон чтобы он проверял типы? Т.е. например требовал чтобы значение было всегда атомом, а второй переменной типа integer?

    • 0
      1. Почему нет? Что вас смущает?

      2. Для этого есть guards. Я думаю, о них автор дальше напишет.
      • 0
        По превому все смущает, пример можно? Т.е. понятно как это сделать например для трех элементов

        all_three_elements_of_list_is_different([_,R,R]) -> false;
        all_three_elements_of_list_is_different([R,_,R]) -> false;
        all_three_elements_of_list_is_different([R,R,_]) -> false;
        all_three_elements_of_list_is_different([_,_,_]) -> true.

        Но для четыре, пяти, шести и больше очень громоздко :)

        По второму пункту — как же -spec для функций? Как раз же получается, что мы можем проверить тип значения? На этапе компиляции правда…

        Ну и опять же у меня есть ощущение, что match specification мне поможет и в первом и во втором случае? Нет?
        • 0
          spec — это для dialyzer, это отдельный статический анализатор, к компилятору имеет весьма опосредованное отношение.
          • 0
            Это понятно, слово «компиляции» в кавычки взять нужно было. Но вопрос открытый — так одно даст проверить, что не тот тип передается или нет. Или с какой-то вероятностью?
            • 0
              А черт его знает. Типы, говорят, годно проверяет, пока все покрыто спеками.

              >> все входящие значения разные
              Не сможет.
        • 0
          2. Как вам поможет spec для сопосотавления с образцом? Вы же хотите разные реализации функции в зависимости от типа аргумаента, правильно я понимаю? С помощью spec же можно проверить, можно такую функцию с такими типа аргументов вызывать в принципе.

          И каким образом вы хотите задействовать тут match specification?
          • 0
            И все же возвращаясь к пункту 1 — как сделать так чтобы матчилось если все элементы списка (или просто все параметры) разные?

            По второму, я спросил — match specification поможет или нет?
            • 0
              Я полагаю, что в общем случае так же, как и в любом другом языке. Сравнением. Сравнение с образцом по сути так же выполняется же — берется первый вариат, проверятся, если не подходит — берется второй вариант и т.д.

              Я не вижу, как вообще match specification сюда прикрутить, но вы его приводите — может, вы чего-то знаете, что я пропустил?
              • 0
                Ну вот смотрите как я рассуждаю, мы можем сделать так

                1> Tmp = ets:new(table, []). 16400 2> ets:insert(Tmp, {1,2,3}). true 3> ets:insert(Tmp, {1,2,1}).

                А потом как нибудь так

                ets:match(Tmp, [{'$1','$2','$3'}, {'>','$3', 2}]).

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

                И я например логично ожидаю что можно было бы описать функцию примерно таким образом

                fun([{'$1','$2','$3'}, {'>','$3', 2}]) ->

                Которая работала бы аналогично — т.е. ожидала триплеты, и матчилась только для триплетов у которых третий элемент больше 2

                Т.е. с одной стороны мы можем по патерну выбирать данные с условиями которые добавлены через ets:insert — с другой не можем так же по такому же паттерну матчить их как входящие параметры функции, а вынуждены делать это через гуарды
  • +6
  • +3
    Всегда считал что «переменные, которые нельзя изменять» называются — именованные константы.
    • 0
      Математика не согласна.
    • +3
      На самом деле там не совсем переменные и не совсем константы. Их нельзя изменить, но им можно сколько угодно раз присвоить (одно и то же) значение.

      Грубо говоря, когда вы вводите новый идентификатор, он не связан ни с каким значением. Операция присваивания или вызов функции производят сопоставление с образцом, связывая при этом несвязанные ранее имена. В дальнейшем, после связывания, присваивание будет просто сопоставлять с образцом.
    • +1
      В англоязычной литературе это обычно называется binding — привязка имени к значению/выражению.
  • +2
    Имхо, лучше что-нибудь на примерах в дальнейшем. Но вообще, это все равно очень полезно! Спасибо.
    • 0
      Примеры обязательно будут. Здесь я тоже старался показывать на примерах (тот же генератор списков), но в данной статье все примеры слишком элементарные.

      Дальше будет интересней, я обещаю.
  • +1
    Почему нельзя сопоставлять уже связанные переменные?
    Вполне же рабочий код
    1> A = 5.
    5
    2> {A, _} = {5, whatever}.
    {5, whatever}
    


    А вот это так вообще бывает очень полезно
    > F = fun([H | _], H) -> ok end. 
  • +3
    Неплохо было бы описать в чем минусы использования "++" и "--" в списках и в каких случаях их использование оправдано, а в каких — нет.

    Извините конечно, но мне кажется что статей по типу введения в ерланг уже просто тонны. Все понятно и разжевано.

    На мой взгляд неплохо было бы увидеть что-нибудь о менее описанных на русском темах типа:
    «Как работает GC»
    «Дебаггинг и профилирование в ерланге»
    «Тонкости отстройки виртуальной машины» и прочее. Плохо освещена тема использования snmp фреймворка.
    • +1
      Возможно, вы не обратили внимание, но во вступлении я писал про это.
      Проблема в том, что в на русском языке кроме таких элементарных вещей большие ничего не описывается. Я планирую описать все, но без основ, знания будут неполными. Потерпите немножко, дальше будут более сложные темы.
      • 0
        отлично, заранее спасибо!
  • 0
    Возможно стоит упомянуть, что для конкатенации строк используется оператор ++ или string:concat(A, B), а также про такой момент:

    > A = "A" .
    > B = "B" .
    > C = 'C' .
    >
    > A ++ B .
    AB 
    >
    > A ++ B ++ C.
    [65,66|'C']
    
    • 0
      Про строки будет в другой статье.
  • +1
    Статья отличная, но про стоки совсем ничего нет. Буду ждать с нетерпением следующие статьи. Желаю автору не останавливаться на достигнутом и перевести весь learyousomeerlangforgreatgoods. Надеюсь когда-нибудь прочитать про FSM в эрланге на русском. И don't drink too much Kool-aid.
  • +2
    Вот тут можно попробовать Erlang без установки.
    • +1
      Вот эту штуку хабраэффектнуть тоже не помешает.
  • 0
    Автор, Erlang это хорошо, но делайте статьи длиннее. Те кому не интересно и так читать не будут, а кто таки захочет прочитать, может осилить и больший объем.
    • +1
      Вы несомненно правы, кому надо — осилят. Но глава должна быть логически целой.
      Плюс к этому у меня самого уходит много времени на написание статей. К примеру на эту я потратил почти неделю (по вечерам после работы). Я не умею выражать свои мысли красиво, поэтому приходится подолгу подбирать слова. Если делать главы еще больше, то писать я их буду очень долго.
      • 0
        Ничего, к концу книги научитесь :)
  • +3
    Лучше learnyousomeerlang.com ничего нет. Читайте лучше оригинал, а не переводы.
  • 0
    Опишите в статье что такое операция «rem». Мне понять что такое «rem» практически невозможно.

    7 rem 3.
    1

    Что сие значит? Остаток от деления с каким-то хитрым округлением вниз?

    Далее она используется вроде как для определения четности, но так же не описана математика, остается только догадываться.
    • +5
      Это обычный остаток от деления, какое тут хитрое округление вы увидели?
      • +1
        Да, затупил я конкретно.
  • –1
    Зачем вся эта тягомотина? Я с трудом себе представляю человека, изучающего эрланг с нуля. Скорее этот человек уже знает N языков. Достаточно было бы: числа такие-то, есть таплы, выглядят так-то, особенности такие-то и т.д. Обычно авторы, пишущие многабукав в начале, подходя к серьёзным вещам, сливаются, запала не хватает.
    • 0
      Вы не поверите, но есть люди для которых эрланг может оказаться первым языком. Я лично знаю пару прграммистов, которые начинали с функциональщины. Тяжело им, конечно, потом пришлось. Все таки для фукциональщиков работы в разы меньше, но ничего — работают.
      И что бы они делали, если бы все учебные пособия были написаны так, как вы говорите?

      Впрочем, я ожидал такой реакции. Даже специально в начале предупредил.
  • +1
    Знаете, я бы для следующей статьи порекомендовал бы придумать пару интересных задач для проектов на эрланге. В виду специфичности языка и круга задач, мне лично при изучении было сложно придумать адекватное применение эрлангу, что бы учить его в боевых условиях. Поэтому вводные части+задания для практики это намного лучше просто описания базовых принципов языка.
    • 0
      Да, присоединяюсь к просьбе.

      Хотелось бы шаг за шагом какую-нибудь крутую штуку сделать :)
      • 0
        Спасибо за совет.
        Я постараюсь придумать что-нибудь интересное и практически полезное.
    • –2
      Вот это точно. Реальных для бизнеса/энтерпрайза пару задачек, чтобы мы, сирые, могли увидеть выгоды/преимущества и функциональных языков в целом, и Эрланга в частности.
      • +3
        Вы смеетесь или серьезно?
        Я все понимаю, примеры необходимы. Но как вы себе представляете пошаговое объяснение языка на примере сложной задачи с непростой логикой? Для решения такой задачи надо, как минимум, составить план. А как составить план, если на данный момент мы будем знать только самые основы?

        Чесно говоря мне уже давно надоели вопросы типа «чем функциональные языки лучше императивных»? Да ничем. Они прсто-напрсто другие. Это как сравнивать синий и зеленый. Любую задачу можно решить на любом языке: где то оптимальнее на императивном, где то на функциональном. Мне ФЯ ближе по образу мышления, вот и нравятся. Но исторически так сложилось, что императивные языки более популярны. Из-за этого подавляющее число алгоритмов описаны в императивном стиле.

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

        Я, к примеру, считаю синтаксис ФЯ более читабельным. А Haskell вооще воплощением лаконичности. А из императивных языков мне только плюсы нравятся. Честное слово, надоели холивары на эту тему.

        Извините меня, пожалуйста, если я вас неправильно понял и это был не сарказм. Накипело.
        • +1
          Никакого сарказма. Мой любимый язык — старый добрый Visual Basic. Процедурщина и объектно-ориентированность. Уже достаточно много лет успешно решаю задачи корпоративного класса. Я понимаю, что каждый инструмент хорош в своей области, вот и заинтересовало, можно ли что-то «условно-реально» полезное для корпоративной среды более элегантно, производительно или с меньшими трудозатратами закодить на Эрланге. Я не прошу разработать и реализовать многоуровневую сложную систему корпоративного класса ) Было бы интересно увидеть красивое решение хотя бы какой-то относительно простой подзадачи. Да хотя бы сортировки, или обработки текста, или матчинга строк, если Эрланг имеет в этой области какие-то сильные стороны… А ещё лучше — небольшой пример из жизни, как этот язык помог решить конкретную проблему.
          • 0
            В одной из ближайших статей, где будет разбираться хвостовая рекурсия, будет классический пример быстрой сортировки в лдну строку.
            В принципе, Эрланг хорош при работе в качестве фронтенда для сетевого приложения. К примеру, принимает подключение, делает какие-нибудь несложные вычисления и передает поток выполнения дальше. Он нужен там, где надо решать очень большое колличество задач параллельно.

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

            P.s. На сколько я знаю, Erlang — не лучший выбор для работы со строками.
            • 0
              Вот и отлично. Спасибо! Ваша статья, кстати, гораздо понятнее книжки по Erlang, которую я не так давно прикупил.
              Естественно, никто и не говорит, что нужно в первой же статье с места в карьер разбирать сложные темы. Речь-то шла о пожеланиях на будущее.
  • –3
    как можно вообще програмировать без изменяемых переменных?
    Допустим у меня есть некий обьект и он имеет координы x, y и он может перемещятся.
    Как мне такое написать на erlang?
    присваивать новые x1, y1? тогда у меня будут уже совсем другие переменные с другим названием.
    а как тогда мне например сравнить вновь полученные координы и любого другого обьекта? как вообше написать сравнение с переменной имя которой не знаешь заранее? (напр. x265)
    • +2
      Объект — процесс в виде ген_сервера, который хранит в себе стейт с координатами. Очевидно, что вы можете изменять стейт через посылку сообщений, либо получать этот стейт через синхронную посылку сообщений же.
      Вы просто попробуйте попрограммировать на ерланге, для этого правда надо слегка повернуть мозг.
      • –2
        Похоже для вас это очевидно легко, а рабочий пример можете скинуть?
        Правда не могу пробывать програмировать без примеров.
        • +2
          А пожалуйста :)

          gist.github.com/2garryn/6745209

          garry@debian:/tmp$ erl
          Erlang R15B03 (erts-5.9.3.1) [source] [64-bit] [smp:4:4] [async-threads:0] [hipe] [kernel-poll:false]

          Eshell V5.9.3.1 (abort with ^G)
          1> c(example).
          {ok,example}
          2> {ok, Pid} = example:start_link().
          {ok,}
          3> example:get_coordinates(Pid).
          {0,0}
          4> example:set_coordinates(Pid, {3,4}).
          ok
          5> example:get_coordinates(Pid).
          {3,4}
          10>
          • 0
            Не хочу показаться навязчивым, но реально поверачиваю мозг в другую сторону, пытаюсь понять как работает ваш пример.
            Мы используем всего 2 метода.
            example:set_coordinates
            example:get_coordinates

            Pid, я так понял, фактически локализирована внутри функций.
            cast и call задаются через хендлер.

            set_coors и get_coors — они откуда взялись…
            и зачем нам handle_info, terminate, code_change и init?

            Сумбур. Пока прочитать код не получается. Буду благодарен за помощь!

            • 0
              Чтобы понять нужно изучить как работает gen_server. Рекомендую прочитать в книге от Джо Армстронга — pragprog.com/book/jaerlang/programming-erlang Там есть глава про основные бехейвиоры OTP.
              В кратце — Функция exampe:start_link/0 c помощью ген_сервера запускает отдельный процесс, пид которого возвращает.
              Это процесс имеет свой собственный стейт. внутри которого хранятся значения X и Y. Стейт — последний аргумент в хендлерах ген_сервера — handle_call, handle_cast, handle_info.

              Присмотритесь к колбеку:
              handle_call(get_coors, _From, Position) ->
                  {reply, Position, Position}.
              


              В Position хранятся текущие координаты.

              Это колбек будет вызван когда вы вызовете функцию
              get_coordinates(Pid) ->
                  gen_server:call(Pid, get_coors).
              


              функции init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3 — их объявления требует behaviour, который вы реализуете. Это примерно как интерфейс в джаве.
              Сорри за сумбурное объяснение. Я уверен, что вам будет все понятно, когда вы разберетесь с gen_server
              • 0
                Спасибо!
                Я уже осилил вторую статью автора и вроде как (с натяжкой) начал понимать что происходит (:
                Книжку обязательно почитаю!
      • 0
        Полностью согласен.
        Все дело в том, что поставленую задачу вы пытаетесь решить методами императивных языков. ФЯ — это не только другие инструменты, но и другой подход, совершенно другой ход мыслей. И бывает сложно их осмыслить после большой практики императивного программирования.
        • –2
          тут был слизливый пост о том что как бы голову я не ломал, ход мыслей не менял — рабочего примера не появится…
          • 0
            Лично у меня на данный момент нет сколько-нибудь сложного кода т.к. на функциональных языках писать начал сравнительно недавно. Да и работы в моем городе на них не найдешь.

            Я сделал у себя пометку на эту тему. Обещаю, что как только начну работать над реальным проектом с использованием ФЯ, я вам напишу и все покажу.
    • 0
      val object = new MovingObject(x: 10, y: -5);
      val movedObject = object.copyWithPosition(x: 0, y: 0);

      В чем Ваша проблема?
  • 0
    Спасибо, про ерланг на русском толкового мало, пишите еще.
  • –5
    (боюсь я ещё долго в плюс по карме не выползу но всёже)
    «Я очень люблю функциональное программирование, и один из моих любимых языков — Erlang. »
    Вы любите язык который не знаете?
    Простите я правда думал что графу «от автора» написыли именно вы…
    Ладно не суть. Это ваще лично дело что любить а что не любить.
    Я опять придераюсь к мелочам. но вы говарите что с появлением работы у вас что-то измениться и вы сможете мне такое показать. Ежели это сейчас нельзя узнать без работы «где-то там» это…
    *шопотом* это прям как комерческая тайна какаято…
    А вы её раскроете, ай-яй-яй… как не хорошо получиться…

    Эх если бы всё было так просто… Я бы уже давно сам програмировал на таком языке… Всё упирается в документацию, дальше которой всё — «весь придуманый код» никто не покажет(рабочий код)… Вы не задумывались почему?

    всё просто его нетУ!
    • 0
      [Удалено]
    • 0
      Если вам хочется почитать код на э-ге — смотрите в erlyvideo/flussonic, rabbitmq, riak, couchdb, ejabberd(не уверен, про него разное говорят). Это все готовые продукты, которые работают и, что немаловажно, приносят своим создателям деньги.
    • +1
      Вот ещё рабочие проекты, с которых можно начать ковыряться:
      github.com/erlang/otp — много интересного, много legacy.
      github.com/jlouis/etorrent_core — классическое Erlang-приложение, торрент-клиент, just for fun.
      github.com/RefactoringTools/Wrangler — работа с AST, интеграция с emacs.
      github.com/zotonic/zotonic — CMS, можно проводить параллели с wordpress.
      • 0
        Это довольно сложные проекты. С OTP начинать ковыряться лучше с документации. И никогда не брать в пример код OTP. Порой он просто адовый
  • 0
    большое спасибо за статью, не взирайте на отзывы типа «зачем эта тягомотина»!
    вопросы по теме:
    1. непонятно какое применение у атомов, зачем они? чем атом отличается от строковой переменной?
    2. чем отличаются «равно»(==) и «соответсвенно равно»(=:=)?
    3. в чем разница по сути кортежа и списка в Эрланге, кроме того что список имеет голову и хвост? почему кортеж не аналог массива (array)?
    • 0
      1. Атом занимает в памяти одно слово. Используются много где. Как имена функций, рекордов, имена модулей итп
      2. По сути «Равно» сравнивает два значения, тогда как «соответственно равно» сравнивает еще и типы.
      Пример:

      1> 3.0 == 3.
      true
      2> 3.0 =:= 3.
      false

      3. Кортеж — неизменяемый набор данных фиксированной длины. А array — это такая стильная модная реализация массивов.
      • –1
        Разница между кортежами и списками Как ее понял я.

        Кортеж создается один раз и потом не может измениться, ни длинна ни содержимое.
        Создается вручную.

        Список имеет голову и хвост может изменяться как длинна так содержимое.
        Интересно как поменять значение определенного елемента списка на другой?
        Создается вручную или с помощью генератора.

        Прошу подтверждения правильности у автора и у 2garryn
        • 0
          Представьте просто, что кортеж (тапл) это массив. Содержимое можно менять функцией setelement/3. Длину менять нельзя.

          Список — это просто односвязный список. На голову и хвост его можно поделить операцией "|"
          Меняется нужный элемент через lists:nth/3
          А вообще стоит почитать литературку)

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.