Комментарии 59
Ключевой момент — unlines fsContents.
Не совсем. Ключевой момент на две строчки ниже — putStrLn (unlines fsContents).
Если это второе использование fsContents вырезать, то всё будет работать в константе памяти (если конечно нет других ошибок). Сборщик мусора должен всё собрать, а ленивый ввод-вывод не допустить полной загрузки содержимого файлов в память.
В хаскеле кроме чистых функций ленивость реализована в операциях ввода-вывода. Внутри merge readFile фактически начнёт читать в тот момент, когда данные потребуются. И будет читать их чанками фиксированного размера. Грубо говоря каждый чанк будет проходить обработку, записываться в writeFile и подчищаться сборщиком мусора. Если после этого на них него других ссылок, а у вас есть.
Не совсем. Ключевой момент на две строчки ниже — putStrLn (unlines fsContents).
Если это второе использование fsContents вырезать, то всё будет работать в константе памяти (если конечно нет других ошибок). Сборщик мусора должен всё собрать, а ленивый ввод-вывод не допустить полной загрузки содержимого файлов в память.
В хаскеле кроме чистых функций ленивость реализована в операциях ввода-вывода. Внутри merge readFile фактически начнёт читать в тот момент, когда данные потребуются. И будет читать их чанками фиксированного размера. Грубо говоря каждый чанк будет проходить обработку, записываться в writeFile и подчищаться сборщиком мусора. Если после этого на них него других ссылок, а у вас есть.
+2
Очень рекомендую эту главу RWH. Помогает бороться с проблемой поедания O(n) памяти. Которой обусловлены почти все проблемы «производительности».
А статья классная, хоть и сумбурная. Бесточечная нотация поначалу совсем не обязательна. И не только по началу.
Других способов получше разобраться с хаскелем как я понимаю нет. После руководств совсем не понятно как всё это используется на практике. Приходится просто писать.
А статья классная, хоть и сумбурная. Бесточечная нотация поначалу совсем не обязательна. И не только по началу.
Других способов получше разобраться с хаскелем как я понимаю нет. После руководств совсем не понятно как всё это используется на практике. Приходится просто писать.
+3
Линуксоиды бы использовали какой-нибудь Bash, Perl или Python, — дешево и сердито, но на Windows-машину их ради одной операции не поставишь, то же самое касается и PowerShell.
Звучит будто Haskell входит в стандартную поставку MS Windows.
Звучит будто Haskell входит в стандартную поставку MS Windows.
+5
Нет, но можно собрать исполняемый файл и использовать его на машине, где Haskell нет. Правда не знаю, можно ли скомпилировать программы на языках Perl и Python. Подозреваю, что можно.
+1
PowerShell даже на Xp ставит банальный Windows Update. И exe с помощью PowerGui собать можно.Но статической типизации там нет, да.
+1
НЛО прилетело и опубликовало эту надпись здесь
На самом деле проблема глубже. Что будет, если человек начинает длительный разговор в одном месяце, а заканчивает в другом? Ему два раза начислится сумма. А заранее знать не можем, трафика за следующий месяц может и не быть. Единственный выход — тарифицировать только запись с признаками, что она конечная, последняя.
+1
>>Линуксоиды бы использовали какой-нибудь Bash, Perl или Python
Эка вы поддели армию кодеров на этих языках )
Эка вы поддели армию кодеров на этих языках )
+2
Кстати что значит «хаскель в реальном мире»?
В этой задаче perl или python подошёл бы ничуть не хуже.
Технических проблем, связанных с написанием любого ПО, в хаскеле давно нет.
А никто не использует его просто потому, что он никому не нужен.
В этой задаче perl или python подошёл бы ничуть не хуже.
Технических проблем, связанных с написанием любого ПО, в хаскеле давно нет.
А никто не использует его просто потому, что он никому не нужен.
0
Думается, именно то и значит. Очевидно, автор не ставил себе цели доказать что-то кому-то — это удел адептов той или иной технологии. Мне показалось, автор попытался просто привести пример использования действительно «из жизни», — и это вполне получилось.
+2
Насчет никому не нужен, не вполне понятно.
Хаскелл жив, развивается, догоняет Эрланг по некоторым возможностям (ForkIO, epoll/kqueue), но при этом является статически типизированным, со средствами метапрограммирования, компилируемым в нативный код, обладает оптимизирующим компилятором с llvm-ным бэкендом, обрастает библиотеками и пакетами, имеет несколько веб-фреймворков и много что еще.
Никому не нужен? А что нужно тогда?
Хаскелл жив, развивается, догоняет Эрланг по некоторым возможностям (ForkIO, epoll/kqueue), но при этом является статически типизированным, со средствами метапрограммирования, компилируемым в нативный код, обладает оптимизирующим компилятором с llvm-ным бэкендом, обрастает библиотеками и пакетами, имеет несколько веб-фреймворков и много что еще.
Никому не нужен? А что нужно тогда?
+3
Никому не нужен в смысле не используется в бизнесе.
Все мейнстримные языки худо-бедно справляются со своими задачами.
Плюс к этому проблема курицы и яйца. На рынке труда нет вакансий инженеров-хаскелистов. Поэтому мало кто интересуется языком. Поэтому никто не использует его в проектах, т.к. боится недостатка кадров. Поэтому на рынке труда нет вакансий.
Все мейнстримные языки худо-бедно справляются со своими задачами.
Плюс к этому проблема курицы и яйца. На рынке труда нет вакансий инженеров-хаскелистов. Поэтому мало кто интересуется языком. Поэтому никто не использует его в проектах, т.к. боится недостатка кадров. Поэтому на рынке труда нет вакансий.
+1
Это верно только в рамках странной предпосылки, что программист программирует обязательно на каком-то определенном языке и не в состоянии использовать другой.
Как выяснилось, на практике людей на хаскелл найти совсем несложно. Определенные преимущества при разработке он дает. Почему бы его не использовать?
Кстати, в бизнесе он используется. Но мало, да.
Как выяснилось, на практике людей на хаскелл найти совсем несложно. Определенные преимущества при разработке он дает. Почему бы его не использовать?
Кстати, в бизнесе он используется. Но мало, да.
+1
Если он программирует на с++, то в состоянии использовать питон. Или с#. Или жаву.
Но другую парадигму он не в состоянии быстро начать использовать.
Просто разобраться хотя бы в нескольких концепциях хаскеля занятие не быстрое. А начать писать код с их помощью можно не известно через какое время. Хотелось бы на практике узнать длительность «втягивания» в процесс разработки на хаскеле с нуля.
Но другую парадигму он не в состоянии быстро начать использовать.
Просто разобраться хотя бы в нескольких концепциях хаскеля занятие не быстрое. А начать писать код с их помощью можно не известно через какое время. Хотелось бы на практике узнать длительность «втягивания» в процесс разработки на хаскеле с нуля.
+2
Ну на практике, какое-то количество людей на рынке знакомы с функциональным программированием и хотели бы его использовать, просто нет шансов его где-то применить, потому что нет вакансий.
И на практике мы хаскелльную вакансию закрыли за неделю, а отклик был достаточный, что бы понять, что проблема с такими кадрами — скорее, страшилка.
Переехать с окамла на хаскелл можно дня за три. Окамл очень простой и осваивается недели за две, как и Эрланг, например. Хаскель, безусловно, сложнее, но писать на нём можно и не владея всеми концепциями; сложные вещи можно осваивать постепенно по мере надобности.
И на практике мы хаскелльную вакансию закрыли за неделю, а отклик был достаточный, что бы понять, что проблема с такими кадрами — скорее, страшилка.
Переехать с окамла на хаскелл можно дня за три. Окамл очень простой и осваивается недели за две, как и Эрланг, например. Хаскель, безусловно, сложнее, но писать на нём можно и не владея всеми концепциями; сложные вещи можно осваивать постепенно по мере надобности.
+1
А у вас это где если не секрет? И что за хаскельная вакансия? Закрыли опытным хаскелистом или переучивали?
+1
Небольшая компания. Разрабатываем собственный продукт и ПО на заказ. Для операторов мобильной связи, например.
Вакансия — писать приложения на хаскелле. Клиент-сервер, работа с железом, веб и проч.
Насчет опытного не уверен, до этого он писал на PHP и вроде бы знал эрланг лучше, чем хаскелл, но это только вопрос практики.
Сейчас у нас пока эрланга больше, чем хаскелла, но я планирую новые проекты в основном начинать на хаскелле, ввиду его преимуществ. Там, где больше смысла использовать эрланг (SMPP, SNMP и прочие библиотеки) — будет эрланг.
Вакансия — писать приложения на хаскелле. Клиент-сервер, работа с железом, веб и проч.
Насчет опытного не уверен, до этого он писал на PHP и вроде бы знал эрланг лучше, чем хаскелл, но это только вопрос практики.
Сейчас у нас пока эрланга больше, чем хаскелла, но я планирую новые проекты в основном начинать на хаскелле, ввиду его преимуществ. Там, где больше смысла использовать эрланг (SMPP, SNMP и прочие библиотеки) — будет эрланг.
+1
Я не знаю, может, я какой-то особенный, но мне хватило пары недель, чтобы понять, как Хаскелль работает и что такое функциональное программирование. При том на первой неделе я уже писал простые арифметические программы вроде факториалов и чисел Фибоначчи. К концу месяца изучения вполне свободно использовал основные монады (IO, Maybe, []). И не заметил особых трудностей в этом языке. Я даже утверждаю, что С++ гораздо сложнее, запутаннее и непрозрачнее. Нормальные программы на нем начинаешь писать позже. Конечно, мы не говорим о качестве моих знаний, приобретенных за месяц, — и в статье убедительно показывается, где они были недостаточными.
Может быть, если это получится, я напишу и о процессе своего «втягивания» с нуля, — но тут история получится не слишком захватывающей. Все обыденно: писал себе и писал каждый день после работы, и как дите радовался, если что-то вдруг ни с того ни с сего заработало. :)
Может быть, если это получится, я напишу и о процессе своего «втягивания» с нуля, — но тут история получится не слишком захватывающей. Все обыденно: писал себе и писал каждый день после работы, и как дите радовался, если что-то вдруг ни с того ни с сего заработало. :)
+1
«…ни с того ни с сего заработало» — это сильно сказано :)
+1
Тут, я думаю, работало подсознание. В самом деле, я писал простенькие арифметические функции по разным примерам, еще не зная, с какой стороны подойти к языку. Просто писал что-то, внутри чего логика связей была такой же, как в примерах, с поправками на свою задачу. И оно почему-то начинало работать…
0
НЛО прилетело и опубликовало эту надпись здесь
Но ведь вам для вашей задачи никто и не предлагал использовать хаскель? Автору захотелось попробовать «чего-то эдакого» — он попробовал и у него получилось. Своими достижениями автор поделился с общественностью. Я не заметил чтобы автор делал какие-то категоричные утверждения касательно необходимости использования той или иной технологии для каких-либо видов задач.
+1
НЛО прилетело и опубликовало эту надпись здесь
Я веду к тому что автор ведь не утверждал, что данная задача подходит для хаскеля или наоборот. Соответственно и пытаться это оспорить просто бессмысленно. Захотелось автору именно такую задачу решить именно на хаскеле — и все дела. А народ начинает спорить о том, какой ЯП больше подходит для данной задачи — да статья-то вообще не об этом!
+1
http://shootout.alioth.debian.org/u64q/benchmark.php?test=all&lang=ghc&lang2=python3
бенчмарки не считают что питон лучше подходит в плане производительности
бенчмарки не считают что питон лучше подходит в плане производительности
+1
По вашей ссылке показывается, что на идентичных задачах питоновский код вдвое короче. Его можно выбрать для некритичных к производительности задач. Возможно, что краткость исходников обусловлена отсутствием статической типизиции.
+1
Для ультимативной скорости при равной кривизне рук хаскель подходит лучше — ибо оптимизирующий компилятор.
Для ультимативной надежности при тех же равных — опять лучше хаскель ибо сильная статическая типизация.
Но если функциональщина еще не вошла в мозг — то рулит питон, повершелл и т.п.
Для ультимативной надежности при тех же равных — опять лучше хаскель ибо сильная статическая типизация.
Но если функциональщина еще не вошла в мозг — то рулит питон, повершелл и т.п.
+1
Подобные файлы скорее всего легко парсятся fsm, а значит, заметного отставания, например, от Си в этом вопросе не будет. Файловый ввод-вывод на байтстрингах тоже не уступает; вот например рассчет sha1 от файла:
этот код работает ровно со скоростью стандартной sha1sum
Хаскелл быстрее и питона, и перла. И у него очень простой и удобный FFI, который позволяет выносить критичные места в Си, если это нужно. Но это нужно крайне редко.
Вот например рассчет crc16 на Haskell и С. Задача для хаскелла нехарактерная, однако справляется не сильно хуже, чем тот же Си. Так что не надо нездорового ажиотажа, Хаскелл — ок. Другое дело, что при наивных реализациях он начинает внезапно сливать. Тот же приведенный выше код рассчета 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 от файла при тупой реализации в лоб жрал память и не завершался. Практика нужна, и всё.
+3
НЛО прилетело и опубликовало эту надпись здесь
Но вы при этом сразу делаете вывод, что хаскелл не подходит.
Хаскелл — язык общего назначения, подходит для очень большого спектра задач. И уж точно файлы парсить и статистику считать он будет, мягко говоря, не хуже, чем некоторые интерпретируемые языки с динамическрой типизацией.
Я не вникал детали того, что конкретно делал автор, но если он не использовал для парсинга своих файлов attoparser или happy/alex или bnfc — значит, скорее всего делал что-то не то, какой смысл парсить это вручную вообще, да еще и медленно.
Хаскелл — язык общего назначения, подходит для очень большого спектра задач. И уж точно файлы парсить и статистику считать он будет, мягко говоря, не хуже, чем некоторые интерпретируемые языки с динамическрой типизацией.
Я не вникал детали того, что конкретно делал автор, но если он не использовал для парсинга своих файлов attoparser или happy/alex или bnfc — значит, скорее всего делал что-то не то, какой смысл парсить это вручную вообще, да еще и медленно.
+2
Тоже самое можно сказать и о Perl, легко ставится под винду, задача как раз для него, и со строками справляется лучше всех =)
не Питоном единым сыты
не Питоном единым сыты
+1
Прочитал о воркарраунде с заменой пробела звездочкой и окончательно убедился, что люди готовы на любое извращение, лишь бы ничего не знать об «этих жутких регэкспах».
* Правда сам грешен сегодня выкусывал из html'a кусок типа $.get(url, function(s){ $("#id").html( $s.substring(s.indexOf('>', s.indexOf('<BODY'))+1, s.indexOf(''))); });
* Правда сам грешен сегодня выкусывал из html'a кусок типа $.get(url, function(s){ $("#id").html( $s.substring(s.indexOf('>', s.indexOf('<BODY'))+1, s.indexOf(''))); });
+1
Можно было бы и регэкспы. Было бы интересно сравнить производительность разных решений.
0
Есть мнение что об «этих жутких регекспах» действительно можно ничего не знать.
Есть такая штука как комбинаторы парсеров. Они легче понимаются чем регекспы, их легче читать. И они позволяют решать гораздо больше задач. Так как могут парсить контекстно свободные грамматики, которые шире чем регулярные грамматики.
Комбинаторы парсеров в питоне, в хаскеле.
Есть такая штука как комбинаторы парсеров. Они легче понимаются чем регекспы, их легче читать. И они позволяют решать гораздо больше задач. Так как могут парсить контекстно свободные грамматики, которые шире чем регулярные грамматики.
Комбинаторы парсеров в питоне, в хаскеле.
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
+1
И так тоже можно было бы…
0
интересно. действительно интересно.
но человека который так решил приведенную задачу я бы на работу не взял, как и человека написавшего регэксп. в этой задаче обычного split выше крыши
но человека который так решил приведенную задачу я бы на работу не взял, как и человека написавшего регэксп. в этой задаче обычного split выше крыши
+1
Я вас не совсем понимаю. split в полной мере используется в новой версии программы. А в начале своего пути я, конечно, дал маху с заменами символов, но это было по неопытности. Вряд ли можно корить начинающего в том, что он начинающий.
0
Это задача парсинга пользовательского ввода.
Сплит это конечно хорошо. Но там ещё нужен один ифник для проверки того, что октетов 4. И ещё проверки того, что не встретились посторонние символы. А может тестировщик найдёт и другие проблемы.
Здесь мы получаем автоматическую генерацию сообщений об ошибках. Введена буква? Библиотека внутри сгенерит ошибку «expected digit». 3 октета вместо 4, будет сгенерина ошибка «unexpected eof, expected digit or '.'», если октетов больше 4, будет сгенерина ошибка «unexpected '.', expected eof». И это всё уже внутри этого кода.
Кроме того, этот подход универсален. Эта функция парсит ip адрес, другие функции в этом модуле точно так же парсят более сложные вещи. Ip-адрес конечно можно распарсить сплитом и регекспом. Но, например, выражение со скобками нельзя.
Используя комбинаторы парсеров везде, мы получаем выйгрыш в универсальности.
Сплит это конечно хорошо. Но там ещё нужен один ифник для проверки того, что октетов 4. И ещё проверки того, что не встретились посторонние символы. А может тестировщик найдёт и другие проблемы.
Здесь мы получаем автоматическую генерацию сообщений об ошибках. Введена буква? Библиотека внутри сгенерит ошибку «expected digit». 3 октета вместо 4, будет сгенерина ошибка «unexpected eof, expected digit or '.'», если октетов больше 4, будет сгенерина ошибка «unexpected '.', expected eof». И это всё уже внутри этого кода.
Кроме того, этот подход универсален. Эта функция парсит ip адрес, другие функции в этом модуле точно так же парсят более сложные вещи. Ip-адрес конечно можно распарсить сплитом и регекспом. Но, например, выражение со скобками нельзя.
Используя комбинаторы парсеров везде, мы получаем выйгрыш в универсальности.
+2
Это смешение теплого и мягкого — сплиты применяются для разбора структурированных данных, регэкспы для быстрой проверки/выкуса конкретного фрагмента.
Более серьезный парсинг требует серьезных средств. Синтаксис регэкспов (если без фанатизма) настолько прост, что нет повода его не применять. Там где он даст выигрыш, например подсчитайте с помощью парсеров количество слова регэксп (и его склонений) в моем посте.
scalar($post =~ /\bрегэксп/mgo);
Более серьезный парсинг требует серьезных средств. Синтаксис регэкспов (если без фанатизма) настолько прост, что нет повода его не применять. Там где он даст выигрыш, например подсчитайте с помощью парсеров количество слова регэксп (и его склонений) в моем посте.
scalar($post =~ /\bрегэксп/mgo);
0
я имел ввиду пример с парсингом ip
а по поводу вашей программы… могу сказать только одно — вы молодец.
любая решенная задача (не важно каким методом или какими средствам) это плюс в карму в реале)
а по поводу вашей программы… могу сказать только одно — вы молодец.
любая решенная задача (не важно каким методом или какими средствам) это плюс в карму в реале)
+2
Чур какашками не кидаться, но у меня парсер access-logs, разбитых с помощью cronolog на файлы по 1 минуте работает достаточно шустро: просто парсинг без базы данных и др. логики — 4 минуты на ~15 млн. записей (лог за месяц).
+1
Ну что вы так сразу — «не кидаться»… Здесь вроде бы культурные люди собрались. А иным Haskell и не интересен. :)
Видимо, это хороший результат — 15 млн. записей за 4 минуты… Но мне кажется, можно было еще быстрее. То есть, у меня 10 сек. = 700 000 записей, 1 мин. = 4 200 000 записей. На 4 минуты это уже 16 млн… То есть, примерно как у вас. Я хочу еще больше оптимизировать свою программу, благо, пути для этого наметились. Если выйдет что-нибудь интересное, опять будет топик. :)
Видимо, это хороший результат — 15 млн. записей за 4 минуты… Но мне кажется, можно было еще быстрее. То есть, у меня 10 сек. = 700 000 записей, 1 мин. = 4 200 000 записей. На 4 минуты это уже 16 млн… То есть, примерно как у вас. Я хочу еще больше оптимизировать свою программу, благо, пути для этого наметились. Если выйдет что-нибудь интересное, опять будет топик. :)
0
Интересно, как некоторые языки прочно привязаны к одной области применения. Например хаскель, эрланг настолько прочно к биллингу в сотовых сетях, что вот и эта статья про биллинг, и в комментариях есть «Небольшая компания. Разрабатываем собственный продукт и ПО на заказ. Для операторов мобильной связи, например.»
В каких еще областях у хаскеля есть success stories? Просто интересно.
В каких еще областях у хаскеля есть success stories? Просто интересно.
+1
На самом деле применения есть, но, конечно, их мало в сравнении с другими языками. На странице «Haskell in industry» приводится несколько десятков успешных программ на Haskell. Из них:
* ИИ для оборонной промышленности
* Обработка ДНК в терапевтической компании
* Симуляторы для тестирования беспроводного оборудования
* В Bank of America Merril Lynch Haskell используется как бэкенд для обработки данных
* И многое другое
* ИИ для оборонной промышленности
* Обработка ДНК в терапевтической компании
* Симуляторы для тестирования беспроводного оборудования
* В Bank of America Merril Lynch Haskell используется как бэкенд для обработки данных
* И многое другое
0
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Haskell в реальном мире