пятница, апреля 20, 2007

Немного по OCaml и Haskell

От людей, пишущих программы на OCaml и Haskell часто слышно о том, что они в 10 строках описали то, что на C++/C#/Java занимало 100 строк, или за 2 недели написали то, что другие делали 2 месяца.

Это — всем известные факты. Программы на любом более менее вменяемом языке, будь то erlang, lisp, python, и т.д., в среднем занимают в 5-10 раз меньше места и, по личному опыту, пишутся в 3-5 раз быстрее.

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

Хотя в OCaml есть чудесный отладчик, позволяющий ходить по программе и вперед и назад, никакой потребности в нем за последние 3 года я не ощутил. Да. За последние 3 года я ни разу не пользовался отладчиком для программ, написанных на OCaml. Он просто не нужен! Если и возникают какие-то непонятки, то все решается отладочной печатью или запуском проблемных мест в интерпретаторе.

Не могу сказать, что мои OCaml-программы никогда не падали. Было такое, но виновата была только C++ часть.

А в целом в OCaml и Haskell вы никогда не встретите:

  • access violation — нет pointer arithmetics;


  • NullPointerException — нет NULL :), а на любые места, где возможен None, компилятор вам укажет;


  • SIGSEGV или BSOD — ну нельзя тут загадить память.

Если вы, как и я, пишете программы, работающие 24 часа в сутки 7 дней в неделю, то такие языки как OCaml или Haskell могут стать очень хорошим подспорьем.

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

32 комментария:

Dmitry комментирует...

Трудно начать писать код на OCaml, Haskell, Erlang в компаниях, в которых уже стандарт-дефакто использовать C/C++/C#/Java. Тут много препонов со стороны других программистов и менеджеров.

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

Но я согласен, что эти языки давно созрели для промышленного программирования, в отличие от Prolog, Scheme, Smalltalk и пр. Никак не могу из трясины Java вылезти, уж очень много доступных библиотек ;(

Dmitry комментирует...

А ты как распределяешь возникающие задачи между OCaml и Haskell, по какому принципу?

lrrr комментирует...

Ну у меня немножко обратный эффект был, как я уже писал -- глубоко в душе я надеялся что хаскель абсолютно все проблемы пофиксит за меня :)

Но в общем то, что программы получаются проще и отладчиком пользоваться приходится меньше -- факт.

lrrr комментирует...

Dmitry>Тут много препонов со стороны других программистов и менеджеров.
Будь я менеджером, я б лично по пальцам бил кувалдой тем кто хочет интенсивно использовать haskell в проекте (кроме как для упомянутых прототипов и утилиток).
Потому что если моего замечательного программиста-хаскеловеда переедет каток или он захочет найти другую работу -- найти ему замену будет или просто нереально или нереально дорого.

Vladimir Shabanov комментирует...

Но я согласен, что эти языки давно созрели для промышленного программирования, в отличие от Prolog, Scheme, Smalltalk и пр. Никак не могу из трясины Java вылезти, уж очень много доступных библиотек ;(

Ну, prolog используется в виндах. На Smalltalk, если ничего не путаю, написана база для аэрофлота. Scheme много где используется как скриптовый язык.

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

Другое дело, что OCaml и Haskell обладают хорошей системой типов и тем самым в разы повышают корректность программ.

Vladimir Shabanov комментирует...

А ты как распределяешь возникающие задачи между OCaml и Haskell, по какому принципу?

В основном я пишу на OCaml. Он несколько проще и привычнее для человека из императивного мира. Если что не знаешь, как написать функционально, всегда можно написать как раньше писал (объекты, циклы, массивы...).

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

В целом выбор достаточно сложен. Оба языка хороши. Хаскел конечно более продвинутый, но и из-за этого более сложный. OCaml проще и производительней. OCaml более практичен, в нем меньше сюрпризов и не надо думать: "а как это будет в чисто функциональном стиле". С другой стороны хаскелл обладает более приятным синтаксисом и программы на нем короче и читабельнее чем на окемл.

Ну и еще есть такой немаловажный фактор, как наличие библиотек. У хаскела из-за его большей популярности их несколько больше. А у Java их просто море :)

Vladimir Shabanov комментирует...

Будь я менеджером, я б лично по пальцам бил кувалдой тем кто хочет интенсивно использовать haskell в проекте (кроме как для упомянутых прототипов и утилиток).

It depends. Как минимум от проекта. А вот если кто-то начнет писать утилитки и прототипы на хаскеле, я бы серьезно поговорил о повышении з/п этому человеку.

Потому что если моего замечательного программиста-хаскеловеда переедет каток или он захочет найти другую работу -- найти ему замену будет или просто нереально или нереально дорого.

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

А нереальность замены. Мне кажется, что имеется достаточное количество людей, которые хотят писать на хаскеле. Причем люди это более продвинутые. Так что стоит разместить вакансию и посмотреть (что я, возможно, и сделаю через некоторое время :).

Vladimir Shabanov комментирует...

Еще по поводу замены. Мне иногда думается, что быстрее человека научить писать на ocaml или haskell (или, на крайняк, python), чем ждать пока он что-то напишет на C++.

lrrr комментирует...

>Кстати, поскольку программа будет написана быстрее, шансы того, что программиста переедет каток уменьшаются.
Хех это в геймдеве, где процесс разработки выглядит как "написал и забыл"(ну кроме MMOG),
во многих других областях глагол "писать программу" не имеет совершенной формы :)

>Мне кажется, что имеется достаточное количество людей, которые хотят писать на хаскеле.
На моих глазах тут уже полтора года ищут не то что хаскельщика -- просто нормального C++ девелопера, безрезультатно. Может, конечно, ищут плохо..

Vladimir Shabanov комментирует...

На моих глазах тут уже полтора года ищут не то что хаскельщика -- просто нормального C++ девелопера, безрезультатно. Может, конечно, ищут плохо..

Эх. Тоже посмотрел вчера резюме на dtf & job.ru, был в ужасе: все еще хуже чем год назад. Видимо придется поискать толкового студента и пущай учит окемл (или хаскелл). Хотя... где искать толкового студента?

Короче, на днях, буду придумывать вакансию. Посмотрим, кто найдется.

Vladimir Shabanov комментирует...

Кстати, еще по поводу поиска специалиста. Вспомнилась статейка Джоэля Спольски, где он говорил, что хорошие специалисты очень редко меняют работу и по-этому их резюме крайне редко попадает вам на глаза.

:( грустно

dulanov комментирует...

Эх. Тоже посмотрел вчера резюме на dtf & job.ru, был в ужасе: все еще хуже чем год назад. Видимо придется поискать толкового студента и пущай учит окемл (или хаскелл). Хотя... где искать толкового студента?

Это тема отдельного разговора. Мы уже три месяца как ищем человека на .NET - полная засада. Такое ощущение, что много программистов уехало за рубеж (только у меня за последний год два знакомых уехали, один в Нью-Йорк, другой на ПМЖ в Австралию). Кроме того, профессия программиста стала менее привлекательна для стедентов. Из программистов многие уходят в менеджеры. Искать очень трудно! А студенты тоже молодцы, каждое третье резюме - готов управлять командой разработкиков и зарплата от $2500 нетто, и смех и грех ;)

Vladimir Shabanov комментирует...

Ммда, думал что хотя бы с .Net дела получше. Он же, вроде как, теперь моден.

Зай комментирует...

lrrr> Будь я менеджером, я б лично по пальцам бил кувалдой тем кто хочет интенсивно использовать haskell в проекте

Не использовать новые технологии - тоже риски. Какие из них большие - это еще надо посмотреть.

Vladimir Shabanov комментирует...

Про риски — это хорошо. Всегда знал, что самый большой риск в проекте на плюсах — это сами плюсы. Но тут в более общей форме.

allegecityrat комментирует...

Вы меня заинтриговали и заинтересовали. Ознакомлюсь, пожалуй — никогда не знаешь, что может пригодиться. Когда-то вот на C# перешел успешно.
И всё же, не понял одну вещь — а каким же это образом они обходятся без null? Бывают же ситуации, когда объект может быть, а может его и не быть (да взять хотя бы nullable fields в базах данных). Дополнительный бульбулевский флажок что ли вводить?!

Vladimir Shabanov комментирует...

Для таких ситуация есть опциональные типы.
В ocaml:
type 'a option = Some 'a | None
В haskell:
data Maybe a = Just a | Nothing

Т.е. напрямую к a обратиться не получится, его надо извлекать (pattern-matching-ом).

А во всех остальных случаях (например открытие файла возвращает сразу файл, не завернутый в опциональный тип), т.к. NULL-а нет ф-я должна или вернуть нормальный ответ или бросить exception.

Анонимный комментирует...

В первые дни изучения Хаскела очень огорчило отсутствие оптимизации хвостовой рекурсии. Ведь даже у недо-функционального Scheme она есть, а у такого гранда - нет!

Roman

Vladimir Shabanov комментирует...

У хаскела есть tail-recursion. Может быть как-то не так была записана ф-ия?

В хаскеле даже нет циклов. Любой рекурсивный алгоритм кодируется рекурсивными ф-иями и без tail-recursion тут никак.

Анонимный комментирует...

Пример программы:

module Main where

f x = x*x + 2*x - 3

int f a b =
let
eps=0.00001
h=(b-a)*eps
sum t s =
if t<=b then
sum (t+h) (s+(f t)*h)
else
s
in sum a 0

main =
let
s=int f 1 4
in print s
Мне кажется, что замыкание sum написано по правилам хвостовой рекурсии.
На WinHugs появляется сообщение
ERROR - C stack overflow
На GHCi (про компилятор и говорить нечего) в Линуксе перестаёт работать сразу, стоит только число eps сделать ещё меньше (например, 0.000001). Сообщение об ошибке подобное.
Странно, о каком стеке в функциональном языке идёт речь? По-моему, сама виртуальная машина сделана неправильно.
Этот пример замечательно работает на Scheme, Erlang и SML (естественно, после переделок под правила синтаксиса соответсвующего языка)

Roman

Vladimir Shabanov комментирует...

Мда. Вот они, ленивые вычисления. Stack overflow здесь возникает из-за большого невычисленного ленивого thunk-а.

Если написать sum (t+h) $! (s+(f t)*h), т.е. добавить $! -- форсированное вычисление аргумента, то все работает.

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

Roman комментирует...

Спасибо за консультацию. Может быть когда-нибудь и воспользуюсь Хаскелом (сам активно работаю со Смолтоком и SML). Хотя не очень понятно, зачем в языке программирования по умолчанию делать ленивые вычисления. Мне больше нравится подход SML, где ленивость включается только тогда, когда мне это действительно нужно (хотя, лично мне это ни разу не пригодилось).

Trams комментирует...

Здравствуйте. Уже пару месяцев присматриваюсь к функциональным языкам. В свободное от учебы и работы время задачки на Хаскеле решал. Хочу изучить Ocaml (собственно пост Ваш нашел таким образом), но меня смущает только одно.
Как у Ocalm обстоит дело с удобным developer enviroment? (Да, признаюсь, привык я к Visual Studio)
Я нашел только плагин к Eclipse, но он очень свеженький.... Посоветуейте-подскажите. Буду благодарен.

P.S. За ссылки о том, как научится думать функционально буду тоже благодарен. (Один рецепт я знаю: practice makes perfect)

Vladimir Shabanov комментирует...

Я (да и многие другие) пользуюсь емаксом для всего (даже для проектов, которые потом компилятся или отлаживаются в VS).

Так что ничего кроме emacs + tuareg mode + ocamlbrowser посоветовать не могу.

Ну и всякие tuareg-овские shortcut-ы в емаксе:
C-c C-s -- запуск интерпретатора.
C-A-x -- пуляние выражения в интерпретатор.
C-c C-c -- компиляция.

Если компилить с опцией -dtypes, то в емаксе потом можно жать C-c C-t для получения информации о типе текущего выражения. Бывает полезно.

Vladimir Shabanov комментирует...

А про научиться думать функционально -- первая глава SICP.

Trams комментирует...

Спасибо. Присмотрюсь к Emacs (я пробовал использовать Eclipse).
Руководствуясь принципом Practice makes perfect пытаюсь использовать Ocaml в учебных проектах. Возник вопрос: как интегрировать его в проект, который пишется на нескольких языках? (Пока что я нашел только одну утилиту для генерации dll, но не успел еще проэксперементировать)
P.S. На самом деле, я уже экспериментировал, но у меня ничего не получилось: я не смог получить cmx (или cmxa) файл.

Vladimir Shabanov комментирует...

Там и не должно быть cmx, там должен получиться обычный сишный объектный файл.

см. Interfacing C with Objective Caml, 18.7.5 Embedding the Caml code in the C code.

Там все компилится с опцией -output-obj, а дальше пишешь обычную dll-ку из которой инициализируешь окемловскую прогу и вызываешь окемловские ф-ии.

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

Yevgeny комментирует...

Думаю что через пару лет Ocaml будет активно популяризован Микрософтом. F# будет включен в комлект поставки с VS2010 а это значит что он будет mainstream...

Анонимный комментирует...

А студенты вообще толковыми бывают?..

Сидя в вузе учишь обычно, что дают. А так, самой - сложно. Лично я - бестолковый студент. Хотя Хаскель поверхностно учить пыталась (и хотя бы ещё один студент пытался местами).
Но толковее как-то не становишься. Я разве что разучилась писать лабы на си

Valdemar комментирует...

Я толковый студент =)

Программированием начал заниматься до универа, поэтому мой опыт берётся не из универа.

Haskell пробую, интересно, пока много чёрных пятен.

Анонимный комментирует...

Трудно наверное также представить, что можно годами писать на С, Java без отладчика?
Этот факт ну никак, даже если за уши тянуть, не связан с Haskell, Ocaml, ФП в целом. Нет в Ocaml ничегошеньки, чтобы этот факт имел место быть в большем степени, чем в ЛЮБОМ другом языке. Это просто OldSchool, и все. Метода работы, если хотите

Vladimir Shabanov комментирует...

Кстати сейчас уже нетрудно. Отладчик -- вещь действительно не очень нужная. Показывает только текущую точку программы, и все, что в ней есть, а надо видеть развитие во времени и только того, что нужно. Текущая точка интересна тогда, когда что-то падает, но тут stack trace & valgrind помогают сильнее отладчика.

Так что действительно, разные метОды.

Однако пункт про то, что в кемле/хаскеле в принципе получается сильно меньше ошибок остается.