Comments 65
Можно ли написать шаблон условие что все входящие значения разные, т.е. например есть для триплетов вида {1,2,3} или {atom1, atom2, atom3} выпонялось, а для триплетов вида {1,1,1} или {atom1, atom2, atom1} нет?
Можно ли написать шаблон чтобы он проверял типы? Т.е. например требовал чтобы значение было всегда атомом, а второй переменной типа integer?
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 мне поможет и в первом и во втором случае? Нет?
И каким образом вы хотите задействовать тут match specification?
По второму, я спросил — match specification поможет или нет?
Я не вижу, как вообще match specification сюда прикрутить, но вы его приводите — может, вы чего-то знаете, что я пропустил?
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 — с другой не можем так же по такому же паттерну матчить их как входящие параметры функции, а вынуждены делать это через гуарды
Понимаю, что не актуально, но всё же.
Спеки предназначены для выявления только некоторых ошибок и помогают выводить типы только приближаясь к выводу типов в языках со статической типизацией; а вы в своей задаче вообще-то с данными работаете, а не с типами ;)
Сопоставление – это не динамическая логика; для обработки списка произвольного размера вам нужно написать функцию.
Ваша реализация как раз и использует функцию и поочередное сопоставление двух значений.
Ваш кейс не очень подходит для сопоставления по образцу, так как сопоставление предполагает работу с известными (образцовыми) данными (а у вас с теми которые не входят в множество известных (не входят в список элементов); то есть вам в любом случае придется сравнивать (сопоставлять) каждый элемент списка с каждым другим элементом списка и сопоставление по образцу вам тут не друг, потому что так называемого "образца" у вас нет.
Задача сравнения элементов списка между собой решаема через сопоставление без использования функций с помощью parse_transform для генерации guard, но только для фиксированной длины списка; либо через итеративную функцию для произвольной длины списка, или с использованием библиотечных функций:
length(List) =:= length(lists:uniq(List))
.
Грубо говоря, когда вы вводите новый идентификатор, он не связан ни с каким значением. Операция присваивания или вызов функции производят сопоставление с образцом, связывая при этом несвязанные ранее имена. В дальнейшем, после связывания, присваивание будет просто сопоставлять с образцом.
Вполне же рабочий код
1> A = 5.
5
2> {A, _} = {5, whatever}.
{5, whatever}
А вот это так вообще бывает очень полезно
> F = fun([H | _], H) -> ok end.
Извините конечно, но мне кажется что статей по типу введения в ерланг уже просто тонны. Все понятно и разжевано.
На мой взгляд неплохо было бы увидеть что-нибудь о менее описанных на русском темах типа:
«Как работает GC»
«Дебаггинг и профилирование в ерланге»
«Тонкости отстройки виртуальной машины» и прочее. Плохо освещена тема использования snmp фреймворка.
Проблема в том, что в на русском языке кроме таких элементарных вещей большие ничего не описывается. Я планирую описать все, но без основ, знания будут неполными. Потерпите немножко, дальше будут более сложные темы.
> A = "A" .
> B = "B" .
> C = 'C' .
>
> A ++ B .
AB
>
> A ++ B ++ C.
[65,66|'C']
Плюс к этому у меня самого уходит много времени на написание статей. К примеру на эту я потратил почти неделю (по вечерам после работы). Я не умею выражать свои мысли красиво, поэтому приходится подолгу подбирать слова. Если делать главы еще больше, то писать я их буду очень долго.
7 rem 3.
1
Что сие значит? Остаток от деления с каким-то хитрым округлением вниз?
Далее она используется вроде как для определения четности, но так же не описана математика, остается только догадываться.
И что бы они делали, если бы все учебные пособия были написаны так, как вы говорите?
Впрочем, я ожидал такой реакции. Даже специально в начале предупредил.
Хотелось бы шаг за шагом какую-нибудь крутую штуку сделать :)
Я все понимаю, примеры необходимы. Но как вы себе представляете пошаговое объяснение языка на примере сложной задачи с непростой логикой? Для решения такой задачи надо, как минимум, составить план. А как составить план, если на данный момент мы будем знать только самые основы?
Чесно говоря мне уже давно надоели вопросы типа «чем функциональные языки лучше императивных»? Да ничем. Они прсто-напрсто другие. Это как сравнивать синий и зеленый. Любую задачу можно решить на любом языке: где то оптимальнее на императивном, где то на функциональном. Мне ФЯ ближе по образу мышления, вот и нравятся. Но исторически так сложилось, что императивные языки более популярны. Из-за этого подавляющее число алгоритмов описаны в императивном стиле.
И человек, который много лет пишет на императивных языках начинает думать на них. И ФЯ кажутся ему неудобными и абсурдными потому, что он смотрит на них через призму императивщины.
Я, к примеру, считаю синтаксис ФЯ более читабельным. А Haskell вооще воплощением лаконичности. А из императивных языков мне только плюсы нравятся. Честное слово, надоели холивары на эту тему.
Извините меня, пожалуйста, если я вас неправильно понял и это был не сарказм. Накипело.
В принципе, Эрланг хорош при работе в качестве фронтенда для сетевого приложения. К примеру, принимает подключение, делает какие-нибудь несложные вычисления и передает поток выполнения дальше. Он нужен там, где надо решать очень большое колличество задач параллельно.
В первых статьях сложных примеров не будет по указанным выше причинам. А после изучения основ, скорее всего сделаю как вы просили. Поставим задачу и будем решать ее параллелно изучению.
P.s. На сколько я знаю, Erlang — не лучший выбор для работы со строками.
Допустим у меня есть некий обьект и он имеет координы x, y и он может перемещятся.
Как мне такое написать на erlang?
присваивать новые x1, y1? тогда у меня будут уже совсем другие переменные с другим названием.
а как тогда мне например сравнить вновь полученные координы и любого другого обьекта? как вообше написать сравнение с переменной имя которой не знаешь заранее? (напр. x265)
Вы просто попробуйте попрограммировать на ерланге, для этого правда надо слегка повернуть мозг.
Правда не могу пробывать програмировать без примеров.
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>
Мы используем всего 2 метода.
example:set_coordinates
example:get_coordinates
Pid, я так понял, фактически локализирована внутри функций.
cast и call задаются через хендлер.
set_coors и get_coors — они откуда взялись…
и зачем нам handle_info, terminate, code_change и init?
Сумбур. Пока прочитать код не получается. Буду благодарен за помощь!
В кратце — Функция 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
Все дело в том, что поставленую задачу вы пытаетесь решить методами императивных языков. ФЯ — это не только другие инструменты, но и другой подход, совершенно другой ход мыслей. И бывает сложно их осмыслить после большой практики императивного программирования.
Я сделал у себя пометку на эту тему. Обещаю, что как только начну работать над реальным проектом с использованием ФЯ, я вам напишу и все покажу.
val movedObject = object.copyWithPosition(x: 0, y: 0);
В чем Ваша проблема?
«Я очень люблю функциональное программирование, и один из моих любимых языков — Erlang. »
Вы любите язык который не знаете?
Простите я правда думал что графу «от автора» написыли именно вы…
Ладно не суть. Это ваще лично дело что любить а что не любить.
Я опять придераюсь к мелочам. но вы говарите что с появлением работы у вас что-то измениться и вы сможете мне такое показать. Ежели это сейчас нельзя узнать без работы «где-то там» это…
*шопотом* это прям как комерческая тайна какаято…
А вы её раскроете, ай-яй-яй… как не хорошо получиться…
Эх если бы всё было так просто… Я бы уже давно сам програмировал на таком языке… Всё упирается в документацию, дальше которой всё — «весь придуманый код» никто не покажет(рабочий код)… Вы не задумывались почему?
всё просто его нетУ!
вопросы по теме:
1. непонятно какое применение у атомов, зачем они? чем атом отличается от строковой переменной?
2. чем отличаются «равно»(==) и «соответсвенно равно»(=:=)?
3. в чем разница по сути кортежа и списка в Эрланге, кроме того что список имеет голову и хвост? почему кортеж не аналог массива (array)?
2. По сути «Равно» сравнивает два значения, тогда как «соответственно равно» сравнивает еще и типы.
Пример:
1> 3.0 == 3.
true
2> 3.0 =:= 3.
false
3. Кортеж — неизменяемый набор данных фиксированной длины. А array — это такая стильная модная реализация массивов.
Кортеж создается один раз и потом не может измениться, ни длинна ни содержимое.
Создается вручную.
Список имеет голову и хвост может изменяться как длинна так содержимое.
Интересно как поменять значение определенного елемента списка на другой?
Создается вручную или с помощью генератора.
Прошу подтверждения правильности у автора и у 2garryn
Erlang для самых маленьких. Глава 1: Типы данных, переменные, списки и кортежи