Как стать автором
Обновить

Комментарии 59

Ключевой момент — unlines fsContents.

Не совсем. Ключевой момент на две строчки ниже — putStrLn (unlines fsContents).
Если это второе использование fsContents вырезать, то всё будет работать в константе памяти (если конечно нет других ошибок). Сборщик мусора должен всё собрать, а ленивый ввод-вывод не допустить полной загрузки содержимого файлов в память.

В хаскеле кроме чистых функций ленивость реализована в операциях ввода-вывода. Внутри merge readFile фактически начнёт читать в тот момент, когда данные потребуются. И будет читать их чанками фиксированного размера. Грубо говоря каждый чанк будет проходить обработку, записываться в writeFile и подчищаться сборщиком мусора. Если после этого на них него других ссылок, а у вас есть.
Безусловно да. Но уже в ревизии 23 эта строчка преобразовалась в следующую:

putStrLn (unlines . take 100 $ processedStrings)

Это чтобы лишнее не выводить. Не скажу, правда, где именно возникают те дополнительные ссылки, которые мешают лениво читать и обрабатывать данные.
Это всё равно ссылка на всю строку, которая непозволит сборщику очистить все элементы строки после 100
А вот ради интереса завтра уберу строку и протестирую программу.
Очень рекомендую эту главу RWH. Помогает бороться с проблемой поедания O(n) памяти. Которой обусловлены почти все проблемы «производительности».

А статья классная, хоть и сумбурная. Бесточечная нотация поначалу совсем не обязательна. И не только по началу.

Других способов получше разобраться с хаскелем как я понимаю нет. После руководств совсем не понятно как всё это используется на практике. Приходится просто писать.
Большое спасибо!

Вообще да, эту главу я еще не читал, но уже почти собирался. Книга весьма хорошая, название этой статьи как бы намекает. :)
Линуксоиды бы использовали какой-нибудь Bash, Perl или Python, — дешево и сердито, но на Windows-машину их ради одной операции не поставишь, то же самое касается и PowerShell.

Звучит будто Haskell входит в стандартную поставку MS Windows.
Нет, но можно собрать исполняемый файл и использовать его на машине, где Haskell нет. Правда не знаю, можно ли скомпилировать программы на языках Perl и Python. Подозреваю, что можно.
Для Perl'а можно, например, использовать PAR::Packer. Сгенерирует .exe-шник, в который будут засунуты все зависимые модули, библиотеки и perl'овый интерпретатор.
Для Питона есть py2exe.
PowerShell даже на Xp ставит банальный Windows Update. И exe с помощью PowerGui собать можно.Но статической типизации там нет, да.
НЛО прилетело и опубликовало эту надпись здесь
На самом деле проблема глубже. Что будет, если человек начинает длительный разговор в одном месяце, а заканчивает в другом? Ему два раза начислится сумма. А заранее знать не можем, трафика за следующий месяц может и не быть. Единственный выход — тарифицировать только запись с признаками, что она конечная, последняя.
>>Линуксоиды бы использовали какой-нибудь Bash, Perl или Python
Эка вы поддели армию кодеров на этих языках )
Кстати что значит «хаскель в реальном мире»?
В этой задаче perl или python подошёл бы ничуть не хуже.

Технических проблем, связанных с написанием любого ПО, в хаскеле давно нет.
А никто не использует его просто потому, что он никому не нужен.
Думается, именно то и значит. Очевидно, автор не ставил себе цели доказать что-то кому-то — это удел адептов той или иной технологии. Мне показалось, автор попытался просто привести пример использования действительно «из жизни», — и это вполне получилось.
Насчет никому не нужен, не вполне понятно.

Хаскелл жив, развивается, догоняет Эрланг по некоторым возможностям (ForkIO, epoll/kqueue), но при этом является статически типизированным, со средствами метапрограммирования, компилируемым в нативный код, обладает оптимизирующим компилятором с llvm-ным бэкендом, обрастает библиотеками и пакетами, имеет несколько веб-фреймворков и много что еще.

Никому не нужен? А что нужно тогда?
Никому не нужен в смысле не используется в бизнесе.

Все мейнстримные языки худо-бедно справляются со своими задачами.

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

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

Кстати, в бизнесе он используется. Но мало, да.
Если он программирует на с++, то в состоянии использовать питон. Или с#. Или жаву.

Но другую парадигму он не в состоянии быстро начать использовать.

Просто разобраться хотя бы в нескольких концепциях хаскеля занятие не быстрое. А начать писать код с их помощью можно не известно через какое время. Хотелось бы на практике узнать длительность «втягивания» в процесс разработки на хаскеле с нуля.
Ну на практике, какое-то количество людей на рынке знакомы с функциональным программированием и хотели бы его использовать, просто нет шансов его где-то применить, потому что нет вакансий.

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

Переехать с окамла на хаскелл можно дня за три. Окамл очень простой и осваивается недели за две, как и Эрланг, например. Хаскель, безусловно, сложнее, но писать на нём можно и не владея всеми концепциями; сложные вещи можно осваивать постепенно по мере надобности.

А у вас это где если не секрет? И что за хаскельная вакансия? Закрыли опытным хаскелистом или переучивали?
Небольшая компания. Разрабатываем собственный продукт и ПО на заказ. Для операторов мобильной связи, например.

Вакансия — писать приложения на хаскелле. Клиент-сервер, работа с железом, веб и проч.

Насчет опытного не уверен, до этого он писал на PHP и вроде бы знал эрланг лучше, чем хаскелл, но это только вопрос практики.

Сейчас у нас пока эрланга больше, чем хаскелла, но я планирую новые проекты в основном начинать на хаскелле, ввиду его преимуществ. Там, где больше смысла использовать эрланг (SMPP, SNMP и прочие библиотеки) — будет эрланг.
Я уже оказывается спрашивал.

Вот и подтверждение тому, что хаскель используют очень ограниченный круг людей.
Кто спорит? Но то, что его не используют другие, не повод же самому не использовать, если вещь годная?
Я не знаю, может, я какой-то особенный, но мне хватило пары недель, чтобы понять, как Хаскелль работает и что такое функциональное программирование. При том на первой неделе я уже писал простые арифметические программы вроде факториалов и чисел Фибоначчи. К концу месяца изучения вполне свободно использовал основные монады (IO, Maybe, []). И не заметил особых трудностей в этом языке. Я даже утверждаю, что С++ гораздо сложнее, запутаннее и непрозрачнее. Нормальные программы на нем начинаешь писать позже. Конечно, мы не говорим о качестве моих знаний, приобретенных за месяц, — и в статье убедительно показывается, где они были недостаточными.

Может быть, если это получится, я напишу и о процессе своего «втягивания» с нуля, — но тут история получится не слишком захватывающей. Все обыденно: писал себе и писал каждый день после работы, и как дите радовался, если что-то вдруг ни с того ни с сего заработало. :)
«…ни с того ни с сего заработало» — это сильно сказано :)
Тут, я думаю, работало подсознание. В самом деле, я писал простенькие арифметические функции по разным примерам, еще не зная, с какой стороны подойти к языку. Просто писал что-то, внутри чего логика связей была такой же, как в примерах, с поправками на свою задачу. И оно почему-то начинало работать…
НЛО прилетело и опубликовало эту надпись здесь
Но ведь вам для вашей задачи никто и не предлагал использовать хаскель? Автору захотелось попробовать «чего-то эдакого» — он попробовал и у него получилось. Своими достижениями автор поделился с общественностью. Я не заметил чтобы автор делал какие-то категоричные утверждения касательно необходимости использования той или иной технологии для каких-либо видов задач.
НЛО прилетело и опубликовало эту надпись здесь
Я веду к тому что автор ведь не утверждал, что данная задача подходит для хаскеля или наоборот. Соответственно и пытаться это оспорить просто бессмысленно. Захотелось автору именно такую задачу решить именно на хаскеле — и все дела. А народ начинает спорить о том, какой ЯП больше подходит для данной задачи — да статья-то вообще не об этом!
По вашей ссылке показывается, что на идентичных задачах питоновский код вдвое короче. Его можно выбрать для некритичных к производительности задач. Возможно, что краткость исходников обусловлена отсутствием статической типизиции.
В этом случае длинна хаскельных исходников обусловлена чрезмерной оптимизацией.
Для ультимативной скорости при равной кривизне рук хаскель подходит лучше — ибо оптимизирующий компилятор.
Для ультимативной надежности при тех же равных — опять лучше хаскель ибо сильная статическая типизация.
Но если функциональщина еще не вошла в мозг — то рулит питон, повершелл и т.п.
Подобные файлы скорее всего легко парсятся fsm, а значит, заметного отставания, например, от Си в этом вопросе не будет. Файловый ввод-вывод на байтстрингах тоже не уступает; вот например рассчет sha1 от файла:

fileHash :: FilePath -> IO FileHash
fileHash f = do
content <- L.readFile f
let hash = H.hashlazy content
return $ concatMap (printf "%02x") (B.unpack hash)


этот код работает ровно со скоростью стандартной sha1sum

Хаскелл быстрее и питона, и перла. И у него очень простой и удобный FFI, который позволяет выносить критичные места в Си, если это нужно. Но это нужно крайне редко.

Вот например рассчет crc16 на Haskell и С. Задача для хаскелла нехарактерная, однако справляется не сильно хуже, чем тот же Си. Так что не надо нездорового ажиотажа, Хаскелл — ок. Другое дело, что при наивных реализациях он начинает внезапно сливать. Тот же приведенный выше код рассчета SHA1 от файла при тупой реализации в лоб жрал память и не завершался. Практика нужна, и всё.

НЛО прилетело и опубликовало эту надпись здесь
Но вы при этом сразу делаете вывод, что хаскелл не подходит.

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

Я не вникал детали того, что конкретно делал автор, но если он не использовал для парсинга своих файлов attoparser или happy/alex или bnfc — значит, скорее всего делал что-то не то, какой смысл парсить это вручную вообще, да еще и медленно.

НЛО прилетело и опубликовало эту надпись здесь
Вы сравнили разный код для разных задач, написанный разными людьми с разным уровнем владения инструментом.
НЛО прилетело и опубликовало эту надпись здесь
Я более чем уверен, что даже моя вторая, эффективная, программа может быть улучшена по многим показателям. Я пока еще не гуру Хаскелля.
Тоже самое можно сказать и о Perl, легко ставится под винду, задача как раз для него, и со строками справляется лучше всех =)
не Питоном единым сыты
Прочитал о воркарраунде с заменой пробела звездочкой и окончательно убедился, что люди готовы на любое извращение, лишь бы ничего не знать об «этих жутких регэкспах».

* Правда сам грешен сегодня выкусывал из html'a кусок типа $.get(url, function(s){ $("#id").html( $s.substring(s.indexOf('>', s.indexOf('<BODY'))+1, s.indexOf(''))); });
Можно было бы и регэкспы. Было бы интересно сравнить производительность разных решений.
Есть мнение что об «этих жутких регекспах» действительно можно ничего не знать.

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

Комбинаторы парсеров в питоне, в хаскеле.

ipAddr :: GenParser Char st Word32
ipAddr = do
    as <- many1 digit
    let a = read as
    when (a > 255) $ fail "ip address octet must be >= 0 && < 256"
    char '.'
    bs <- many1 digit
    let b = read bs
    when (b > 255) $ fail "ip address octet must be >= 0 && < 256"
    char '.'
    cs <- many1 digit
    let c = read cs
    when (c > 255) $ fail "ip address octet must be >= 0 && < 256"
    char '.'
    ds <- many1 digit
    let d = read ds
    when (d > 255) $ fail "ip address octet must be >= 0 && < 256"
    eof
    return $ shiftL a 24 + shiftL b 16 + shiftL c 8 + d
И так тоже можно было бы…
интересно. действительно интересно.

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

Сплит это конечно хорошо. Но там ещё нужен один ифник для проверки того, что октетов 4. И ещё проверки того, что не встретились посторонние символы. А может тестировщик найдёт и другие проблемы.

Здесь мы получаем автоматическую генерацию сообщений об ошибках. Введена буква? Библиотека внутри сгенерит ошибку «expected digit». 3 октета вместо 4, будет сгенерина ошибка «unexpected eof, expected digit or '.'», если октетов больше 4, будет сгенерина ошибка «unexpected '.', expected eof». И это всё уже внутри этого кода.

Кроме того, этот подход универсален. Эта функция парсит ip адрес, другие функции в этом модуле точно так же парсят более сложные вещи. Ip-адрес конечно можно распарсить сплитом и регекспом. Но, например, выражение со скобками нельзя.

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

Более серьезный парсинг требует серьезных средств. Синтаксис регэкспов (если без фанатизма) настолько прост, что нет повода его не применять. Там где он даст выигрыш, например подсчитайте с помощью парсеров количество слова регэксп (и его склонений) в моем посте.

scalar($post =~ /\bрегэксп/mgo);

я имел ввиду пример с парсингом ip

а по поводу вашей программы… могу сказать только одно — вы молодец.

любая решенная задача (не важно каким методом или какими средствам) это плюс в карму в реале)
Чур какашками не кидаться, но у меня парсер access-logs, разбитых с помощью cronolog на файлы по 1 минуте работает достаточно шустро: просто парсинг без базы данных и др. логики — 4 минуты на ~15 млн. записей (лог за месяц).
Ну что вы так сразу — «не кидаться»… Здесь вроде бы культурные люди собрались. А иным Haskell и не интересен. :)

Видимо, это хороший результат — 15 млн. записей за 4 минуты… Но мне кажется, можно было еще быстрее. То есть, у меня 10 сек. = 700 000 записей, 1 мин. = 4 200 000 записей. На 4 минуты это уже 16 млн… То есть, примерно как у вас. Я хочу еще больше оптимизировать свою программу, благо, пути для этого наметились. Если выйдет что-нибудь интересное, опять будет топик. :)
Если ценой одного рабочего дня производительность поднимется на 10% для операции периодической и некритичной — то ну его нафиг такую оптимизацию :) Есть куча критичных задач, да и сервера свои и за процессорное время и т.д. мы не платим.
Ну а у меня это просто повод изучить оптимизацию в Haskell.
Интересно, как некоторые языки прочно привязаны к одной области применения. Например хаскель, эрланг настолько прочно к биллингу в сотовых сетях, что вот и эта статья про биллинг, и в комментариях есть «Небольшая компания. Разрабатываем собственный продукт и ПО на заказ. Для операторов мобильной связи, например.»

В каких еще областях у хаскеля есть success stories? Просто интересно.
На самом деле применения есть, но, конечно, их мало в сравнении с другими языками. На странице «Haskell in industry» приводится несколько десятков успешных программ на Haskell. Из них:

* ИИ для оборонной промышленности
* Обработка ДНК в терапевтической компании
* Симуляторы для тестирования беспроводного оборудования
* В Bank of America Merril Lynch Haskell используется как бэкенд для обработки данных
* И многое другое

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории