Posts tagged ‘erlang’

Психи

Решил выяснить, откуда на свежеустановленной Ubuntu 10.04/Desktop взялся установленный ерланг.
Вскрытие показало, что автоматом ставится gwibber. Это такая приблуда для микроблоггинга.
Которая написана на Питоне и, похоже, испоьзует python-desktopcouch.
Который, понятно дело, использует desktopcouch.
Которая использует couchdb-bin.
Которая написана на ерланге.

И эти люди вынесли из стандартной установки Gimp со смехотворной мотивацией, что он много места занимает…

Aho–Corasick string matching algorithm

Потребовалось тут – реализовал.

Причем оно, на самом деле, на строки не завязано.

ahocorasik:match([[{1,2,3}],[{3,2,1}], [{3,3,3},{1,2,3}]],[{1,2,3},4,5,6,7,8,{3,3,3},{1,2,3}]).
[{[{1,2,3}],[1,8]},{[{3,3,3},{1,2,3}],[7]}]

Continue reading ‘Aho–Corasick string matching algorithm’ »

Расстояние Левенштейна

Хорошая реализация. Главное – быстрая. А то я тут “в лоб” написал было. Всё хорошо, но на 1000 элементах мой вариант ушёл в несознанку. Еще-бы…

Только это не чистый Левенштейн, это Дамерау — Левенштейн.
Спёр себе, что-б было.
Continue reading ‘Расстояние Левенштейна’ »

dict vs lists

Стало интересно, в какой момент имеет переходить с простых списков на dict.

Проверил.

Из за того, что timer:tc точнее 1 микросекунды не считает, пришлось
для каждого варианта считать время выполнения 100 одинаковых операций.
Каждая такая итерация делалась 100000 раз и бралось среднее.

dict:find: при любом размере время выполнения 50-70 микросекунд
(напоминаю, это на 100 подряд вызовах, т.е. один вызов – где-то 0,5 -
0,7).

lists:keyfind:
номер элемента – время (здесь тоже помним про 100 вызовов).
1 – 4
10 – 8
20 – 12
30 – 15
100 – 46
150 – 67
200 – 87
300 – 130

Вобщем, где-то начиная с 300 элементов в списке имеет смысл переходить
на dict (если, конечно, нам не нужен постоянно последний элемент).

Откуда у хлопца испанская грусть

Я попытаюсь объяснить что именно меня заставляет постоянно испытывать когнитивный диссонанс при написании на ерланге. И пример из “Erlang programming” очень для этого подходит:

Допустим мы пишем функцию возвращающую номер месяца по его имени:

month('January') -> 1;
month('February') -> 2;
...
month('December') -> 12.

Что произойдёт, если вызвать эту функцию с “неправильным” параметром? Процесс упадёт, так как Ерланг не найдёт подходящей функции. А дальше у меня возникает “естественное” желание это отловить. Варианта три:
Совсем неправильный вариант – дописать

month(_other) -> {error, badmonth}.

Чуть менее неправильный вариант – переписать всё вот так:

month('January') -> {ok, 1};
month('February') -> {ok, 2};
...
month('December') -> {ok, 12};
month(_other) -> {error, badmonth}.

Особо изощренный неправильный вариант:

try
    M = month(MonthName)
catch
    _:_ -> ....
end

Есть еще варианты, но это, на самом деле, не важно. Потому что в этом месте ловить эту ошибку не нужно. Совсем не нужно. Оно должно упасть и пусть себе падает, всё равно никакого другого разумного выхода из этой ситуации нет, кроме как упасть и перезапуститься.
А почему приходится себя заставлять не делать эти проверки – это как раз “тяжелое наследие C/Pascal и иже с ним”. Когда в течение многих лет приходилось помнить, что malloc может вернуть не только указатель, что fopen может вернуть не только хендл файла, когда неправильные параметры могут привести к не предсказуемым результатам.

Впрочем, я думаю, что у людей, которые начинали с чего-то более адекватного, хотя-бы с C++, я уж молчу про всякие Явы, нет такой проблемы. Они изначально знают, что функция или вернет что просят, или вывалится.

Распечатать и повесить на стену.

Do not future-proof your code. Don’t try to write code that will be able to deal with
every possible eventuality as the system evolves. It will make your code harder to un-
derstand and maintain, adding unnecessary complexity.

Но писать после этого на “обычных” языках становится немного сложно.

Старый стал

30 строк кода в день – маловато как-то.
С другой стороны – иногда оно вот такое:

 Continue reading ‘Старый стал’ »

Очень не хватает

языка программирования с транзакциями.

Что бы можно было для функции написать три “тела” – что делать в обычном случае, что делать в случае “отката” и что делать в случае “откат не удался”. Приходится писать настолько феерически некрасиво и многословно, отрабатывая на каждом шагу каждый чих, что в результате основной алгоритм теряется в нагромождении if/case/try.

Впрочем, ерланговый подход “дай ему умереть” помогает с этим не то что бы справиться, но, по крайней мере, как-то упорядочить. Особенно если придерживаться еще одного правила – “молчи, если не спрашивают” (т.е. функция set(some, value) не должна ничего возвращать никогда).

Попутно задумался о применимости dz-товского фантома. Может я, конечно, чего-то не понимаю, но по моим ощущениям применимость идеи фантома ограничена случаем “нечто в себе с очень ограниченным взаимодействием со внешним миром”. Ну т.е. настолько редкий и мизерный выигрыш от пресловутой persistence, что даже не смешно.

На сколько, всё таки, выразительный язык, да.

case S#s.status of
    [_|_] ->
         send_error(S);

Непонятка

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