Re[2]: Ленивые языки - за и против
От: Gaperton http://gaperton.livejournal.com
Дата: 22.12.08 21:51
Оценка:
Здравствуйте, vshabanov, Вы писали:

G>>Короче, я сторонник контроля над оружием, тьфу, явного управления ленивостью, посредством фьючерсов и стримов (ленивых списков), и строгости по умолчанию.


V>Насчет строгости по-умолчанию. У меня, к примеру, есть небольшой DSL для описания конечных автоматов (типа FRP).


Зачет, первый человек ведет дискуссию по правилам.

V>На Хаскеле типичный код будет выглядеть так:

V>
V>-- | переключалка между несколькими сценами
V>scene = state1
V>    where state1 = switch scene1 [event1 --> state2,
V>                                  event2 --> state3]
V>          state2 = switch scene2 [event3 --> ...]
V>          ...
V>          stateN = ...

V>-- | тупой счетчик
V>counter n = switch (pure n) [tick --> counter (n+1)]
V>


V>Здесь state1..N/counter и т.д. -- это обычные ленивые хаскельные выражения. Спокойно взаиморекурсивно ссылаются друг на друга.


V>В кемле (и в любом eager языке) так сделать не получится. Не даст он запросто выражениям ссылаться друг на друга


Отвечу кратко. Пример с серией выражений, ссылающихся на результаты друг друга, делается в строгом по умолчанию языке с опциональной аннотацией ленивости элементарно. Аналогичный код в "строгом Хаскеле", с предлагаемой (примерной) аннотацией ленивости.

V>
V>-- | переключалка между несколькими сценами
V>scene = state1
V>    where state1 = ? switch scene1 [event1 --> state2,
V>                                  event2 --> state3]
V>          state2 = ? switch scene2 [event3 --> ...]
V>          ...
V>          stateN = ? ...

Разница только в том, что места, где вы полагаетесь на ленивость, указаны явно. А не наоборот. И все. Насчет счетчика, я уверен, вы сами проставите ленивость, где надо. ? - говорит о том, что вычисления на том же уровне ленивы. Его scope ограничен скобками, например.

V>-- | тупой счетчик
V>counter n = switch (pure n) [tick --> counter (n+1)]
V>
Re[20]: Ленивые языки - за и против
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 23.12.08 02:21
Оценка: 1 (1)
Здравствуйте, dmz, Вы писали:

dmz>А с другой стороны, где нибудь есть success stories окамла?


Из того же треда:
Debian and Ubuntu registered installs
-------------------------------------
184,574: FFTW (14,298 lines of OCaml)
 12,866: Unison (23,993 lines of OCaml)
  7,286: MLDonkey (171,332 lines of OCaml)
  4,365: Darcs (3,939 lines of Haskell)
  4,066: FreeTennis (7,419 lines of OCaml)
  4,057: Planets (3,296 lines of OCaml)
  3,465: HPodder (2,225 lines of Haskell)
  2,965: LEdit (2,048 lines of OCaml)
  2,822: Hevea (11,596 lines of OCaml)
  2,657: Polygen (1,331 lines of OCaml)


Плюс множество (в основном исследовательских) компиляторов (джавы, оберона, Haxe и др.) и интерпретаторов. Плюс внутреннее использование компаниями (Janse St. Capital, Lexifi, Merjis, ...). Про эти компании по крайней мере можно найти довольно подробные рассказы об использовании окамла. Merjis, например, обрабатывает десятки гигов данных с его помощью.
Re[3]: Ленивые языки - за и против
От: vshabanov http://vshabanov-ru.blogspot.com
Дата: 23.12.08 12:36
Оценка:
Здравствуйте, Gaperton, Вы писали:

G>Здравствуйте, vshabanov, Вы писали:


G>>>Короче, я сторонник контроля над оружием, тьфу, явного управления ленивостью, посредством фьючерсов и стримов (ленивых списков), и строгости по умолчанию.


V>>Насчет строгости по-умолчанию. У меня, к примеру, есть небольшой DSL для описания конечных автоматов (типа FRP).


G>Зачет, первый человек ведет дискуссию по правилам.


V>>На Хаскеле типичный код будет выглядеть так:

V>>
V>>-- | переключалка между несколькими сценами
V>>scene = state1
V>>    where state1 = switch scene1 [event1 --> state2,
V>>                                  event2 --> state3]
V>>          state2 = switch scene2 [event3 --> ...]
V>>          ...
V>>          stateN = ...

V>>-- | тупой счетчик
V>>counter n = switch (pure n) [tick --> counter (n+1)]
V>>


V>>Здесь state1..N/counter и т.д. -- это обычные ленивые хаскельные выражения. Спокойно взаиморекурсивно ссылаются друг на друга.


V>>В кемле (и в любом eager языке) так сделать не получится. Не даст он запросто выражениям ссылаться друг на друга


G>Отвечу кратко. Пример с серией выражений, ссылающихся на результаты друг друга, делается в строгом по умолчанию языке с опциональной аннотацией ленивости элементарно. Аналогичный код в "строгом Хаскеле", с предлагаемой (примерной) аннотацией ленивости.


Да собственно там, где в кемле появились ф-ии, возвращающие выражения, это и есть почти lazy annotation-ы (только не lazy, а просто ф-ии, т.к. вычисляются всегда строго один раз, многократно форсить не надо).

V>>
V>>-- | переключалка между несколькими сценами
V>>scene = state1
V>>    where state1 = ? switch scene1 [event1 --> state2,
V>>                                  event2 --> state3]
V>>          state2 = ? switch scene2 [event3 --> ...]
V>>          ...
V>>          stateN = ? ...
V>>


G>Разница только в том, что места, где вы полагаетесь на ленивость, указаны явно. А не наоборот. И все. Насчет счетчика, я уверен, вы сами проставите ленивость, где надо. ? — говорит о том, что вычисления на том же уровне ленивы. Его scope ограничен скобками, например.


Но фишка в том, что эти lazy annotation-ы надо еще думать, где вставлять. У меня например есть программист junior, который прогал только на Си и хаскеле. После хаскела ему тяжко объяснять, что тут из-за неленивости надо дополнительные фишки писать. При этом, когда он писал на хаскеле, единственной проблемой (неожиданностью), связанной с ленивостью, было закрытие файла до того, как он был обработан. Так что у всех разный опыт.

В общем я остаюсь при мнении, что ленивость позволяет писать уровнем выше (не говоря уж о том, что у Хаскелла в принципе уровень выше).

Если же нужна большая уверенность в отсутствии невычисленных цепочек, и она нужнее скорости разработки, то чтож, надо использовать strict языки.

V>>
V>>-- | тупой счетчик
V>>counter n = switch (pure n) [tick --> counter (n+1)]
V>>
Re[4]: Ленивые языки - за и против
От: Аноним  
Дата: 24.12.08 00:59
Оценка:
Здравствуйте, vshabanov, Вы писали:

V>Здравствуйте, Gaperton, Вы писали:


G>>Здравствуйте, vshabanov, Вы писали:


G>>>>Короче, я сторонник контроля над оружием, тьфу, явного управления ленивостью, посредством фьючерсов и стримов (ленивых списков), и строгости по умолчанию.


V>>>Насчет строгости по-умолчанию. У меня, к примеру, есть небольшой DSL для описания конечных автоматов (типа FRP).


G>>Зачет, первый человек ведет дискуссию по правилам.


G>>Разница только в том, что места, где вы полагаетесь на ленивость, указаны явно. А не наоборот. И все. Насчет счетчика, я уверен, вы сами проставите ленивость, где надо. ? — говорит о том, что вычисления на том же уровне ленивы. Его scope ограничен скобками, например.


V>Но фишка в том, что эти lazy annotation-ы надо еще думать, где вставлять. У меня например есть программист junior, который прогал только на Си и хаскеле. После хаскела ему тяжко объяснять, что тут из-за неленивости надо дополнительные фишки писать. При этом, когда он писал на хаскеле, единственной проблемой (неожиданностью), связанной с ленивостью, было закрытие файла до того, как он был обработан. Так что у всех разный опыт.


V>В общем я остаюсь при мнении, что ленивость позволяет писать уровнем выше (не говоря уж о том, что у Хаскелла в принципе уровень выше).


V>Если же нужна большая уверенность в отсутствии невычисленных цепочек, и она нужнее скорости разработки, то чтож, надо использовать strict языки.


Да, ты верно говоришь, что у хаскеля другой уровень и другая область применения. Никто не станет писать ray-tracer на erlang, и от того, что erlang медленнее хаскеля/clean/etc в какой-то области его никто не станет выбрасывать, так как он затачивался под другие задачи.

Но, к сожалению, всё дискусия построенна на том, что Gaperton тупо игнорирует вопросы о подразумеваемой им области применения в которых он считает, что ленивость по-умолчанию не нужна. Про интенсивные вычисления и реал-тайм понятно, но опять же, cpu-hungry код выносится в либы и используется через FFI, а всю логику и описание control flow можно писать уже на другом языке.

Именно поэтому что-то обьяснить ему не получится — так как всегда можно найти примеры, где ленивость не нужна (опять же, real-time приложения, интенсивные вычисления и т.п.). Вот так и получается, что раз "плоской" отвёрткой крутить шурупы с другим шлицом неудобно, то отвёртку нужно выбрость, потому что она больно не универсальная, и ещё нужно думать, какие отвёртки выбирать.
Re[5]: Ленивые языки - за и против
От: FR  
Дата: 24.12.08 04:28
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Да, ты верно говоришь, что у хаскеля другой уровень и другая область применения. Никто не станет писать ray-tracer на erlang, и от того, что erlang медленнее хаскеля/clean/etc в какой-то области его никто не станет выбрасывать, так как он затачивался под другие задачи.


Вот мне как раз интересна реальная область применения Хаскеля. И я пока вижу что она очень узка и в основном сводится к прототипированию и компиляторам.
Re[6]: Ленивые языки - за и против
От: Аноним  
Дата: 24.12.08 04:33
Оценка:
Здравствуйте, FR, Вы писали:

FR>Вот мне как раз интересна реальная область применения Хаскеля. И я пока вижу что она очень узка и в основном сводится к прототипированию и компиляторам.


Я тут дал ссылок: http://www.rsdn.ru/forum/message/3226635.1.aspx
Автор: z00n
Дата: 24.12.08

там найдется пара релевантных статей
Re[5]: Ленивые языки - за и против
От: Gaperton http://gaperton.livejournal.com
Дата: 24.12.08 09:59
Оценка: 8 (3)
Здравствуйте, Аноним, Вы писали:

А>Да, ты верно говоришь, что у хаскеля другой уровень и другая область применения. Никто не станет писать ray-tracer на erlang, и от того, что erlang медленнее хаскеля/clean/etc в какой-то области его никто не станет выбрасывать, так как он затачивался под другие задачи.


А>Но, к сожалению, всё дискусия построенна на том, что Gaperton тупо игнорирует вопросы о подразумеваемой им области применения в которых он считает, что ленивость по-умолчанию не нужна. Про интенсивные вычисления и реал-тайм понятно, но опять же, cpu-hungry код выносится в либы и используется через FFI, а всю логику и описание control flow можно писать уже на другом языке.


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

В больших программах на Хаскеле встречаются трудноуловимые утечки памяти, независимо от области применения. Чтоб нам было на эти проблемы плевать, "область применения" в результате не может являться:
1) Долгоработающим приложением. Все сервера 24х7 идут лесом в колонну по два. Все настольные аппликухи, которые могут долго работать — за ними.
2) Интерактивным приложением с софт-рилтайм гарантиями. Телеком, сетевые приложения, трейдинг, задачи управления и контроля идут лесом.
3) Приложением, которые работает в условиях ограниченных ресурсов. Embedded-разработка, обработка больших объемов данных — все лесом.

Остаются быстро работающие консольные аппликухи, которые не ограниченны памятью, и не жуют обчень больших данных. Только в данном классе приложений нам данная проблема не доставит проблем. Офигенный "класс приложений". Рекомендую.

А>Именно поэтому что-то обьяснить ему не получится — так как всегда можно найти примеры, где ленивость не нужна (опять же, real-time приложения, интенсивные вычисления и т.п.). Вот так и получается, что раз "плоской" отвёрткой крутить шурупы с другим шлицом неудобно, то отвёртку нужно выбрость, потому что она больно не универсальная, и ещё нужно думать, какие отвёртки выбирать.


Объяснить ничего не получается, если не понимаешь, о чем идет разговор. Сочувствую. Я нигде не говорил, что "ленивость не нужна". Я говорил, что у полной ленивости по умолчанию есть проблемы. Это очень сложно понять? Очень сложно, блин, не заметить разницы между этими двумя тезисами?
Re[6]: Ленивые языки - за и против
От: Qbit86 Кипр
Дата: 24.12.08 10:23
Оценка:
G>В больших программах на Хаскеле встречаются трудноуловимые утечки памяти, независимо от области применения. Чтоб нам было на эти проблемы плевать, "область применения" в результате не может являться:
G>1) Долгоработающим приложением. Все сервера 24х7 идут лесом в колонну по два. Все настольные аппликухи, которые могут долго работать — за ними.
G>2) Интерактивным приложением с софт-рилтайм гарантиями. Телеком, сетевые приложения, трейдинг, задачи управления и контроля идут лесом.
G>3) Приложением, которые работает в условиях ограниченных ресурсов. Embedded-разработка, обработка больших объемов данных — все лесом.

А как обстоят дела у Хаскеля с созданием GUI-приложений? Есть ли поддержка со стороны среды, библиотеки, фреймворки? Каковы принципиальные трудности?
Глаза у меня добрые, но рубашка — смирительная!
Re[4]: Ленивые языки - за и против
От: Gaperton http://gaperton.livejournal.com
Дата: 24.12.08 10:25
Оценка:
Здравствуйте, vshabanov, Вы писали:

V>Здравствуйте, Gaperton, Вы писали:


G>>Здравствуйте, vshabanov, Вы писали:


G>>>>Короче, я сторонник контроля над оружием, тьфу, явного управления ленивостью, посредством фьючерсов и стримов (ленивых списков), и строгости по умолчанию.


V>>>Насчет строгости по-умолчанию. У меня, к примеру, есть небольшой DSL для описания конечных автоматов (типа FRP).


G>>Зачет, первый человек ведет дискуссию по правилам.


V>>>На Хаскеле типичный код будет выглядеть так:

V>>>
V>>>-- | переключалка между несколькими сценами
V>>>scene = state1
V>>>    where state1 = switch scene1 [event1 --> state2,
V>>>                                  event2 --> state3]
V>>>          state2 = switch scene2 [event3 --> ...]
V>>>          ...
V>>>          stateN = ...

V>>>-- | тупой счетчик
V>>>counter n = switch (pure n) [tick --> counter (n+1)]
V>>>


V>>>Здесь state1..N/counter и т.д. -- это обычные ленивые хаскельные выражения. Спокойно взаиморекурсивно ссылаются друг на друга.


V>>>В кемле (и в любом eager языке) так сделать не получится. Не даст он запросто выражениям ссылаться друг на друга


G>>Отвечу кратко. Пример с серией выражений, ссылающихся на результаты друг друга, делается в строгом по умолчанию языке с опциональной аннотацией ленивости элементарно. Аналогичный код в "строгом Хаскеле", с предлагаемой (примерной) аннотацией ленивости.


V>Да собственно там, где в кемле появились ф-ии, возвращающие выражения, это и есть почти lazy annotation-ы (только не lazy, а просто ф-ии, т.к. вычисляются всегда строго один раз, многократно форсить не надо).


Не совсем. С ними, например, не должно получится кольцевую ссылку устроить. Вот так:

x = f1 a b y
y = f2 x a b

Это довольно типовой код в случае, если мы побили систему на набор функций, которые связанны ленивыми списками. Данный код — задает "коммутацию" схемы из функций, простым и понятным образом.

Ни, и верятно, у этих функций довольно странный и неприятный тип. Что должно быть неудобно. Доступ к ленивости должен быть очень простой.

G>>Разница только в том, что места, где вы полагаетесь на ленивость, указаны явно. А не наоборот. И все. Насчет счетчика, я уверен, вы сами проставите ленивость, где надо. ? — говорит о том, что вычисления на том же уровне ленивы. Его scope ограничен скобками, например.


V>Но фишка в том, что эти lazy annotation-ы надо еще думать, где вставлять.

Точно. Именно так.

V>У меня например есть программист junior, который прогал только на Си и хаскеле. После хаскела ему тяжко объяснять, что тут из-за неленивости надо дополнительные фишки писать. При этом, когда он писал на хаскеле, единственной проблемой (неожиданностью), связанной с ленивостью, было закрытие файла до того, как он был обработан. Так что у всех разный опыт.


А этот junior сможет найти и устранить невычисленную цепочку, когда она появится? А вы — сможете? Вот thesz в свое время не смог.
http://thesz.livejournal.com/484854.html

Время сборки мусора для копирующего сборщика (как в случае с ghc) пропорционально количеству живых данных. Если это количество все время растет (утечка), то время выполнения программы также начинает расти, причем квадратично — за время δT полезной работы мы добавляем δM байт к уже имевшимся ранее M байт и время работы сборщика становится t+δt. И в нашем случае так и было, причем формула зависимости времени работы для выполнения N команд процессора имела вид наподобие 0.0000001*N2+0.00016*N+0.7. Некоторое время на разогрев (ассемблирование и подготовка образа памяти), 6000 команд в секунду на старте и учет времени сборки утечки.

Большинство тестов укладывалось в 100000 тактов эмулируемого процессора (время ожидания более часа).

Где была утечка, я так и не нашел.


И наконец, разве junior-у не надо понимать, почему именно работает его программа? Если он это понимает, расстановка ленивости не вызовет у него проблем. И поможет потом читателю.

V>В общем я остаюсь при мнении, что ленивость позволяет писать уровнем выше (не говоря уж о том, что у Хаскелла в принципе уровень выше).


Да, позволяет. Я с этим и не спорю. А еще она дает прикольные лики, если лениво все подряд.

V>Если же нужна большая уверенность в отсутствии невычисленных цепочек, и она нужнее скорости разработки, то чтож, надо использовать strict языки.


Ну да. Желательно — с "родной" опциональной ленивостью на уровне языка. Или хотя бы фьючерами.
Re[6]: Ленивые языки - за и против
От: geniepro http://geniepro.livejournal.com/
Дата: 24.12.08 11:00
Оценка:
Здравствуйте, Gaperton, Вы писали:

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


Насколлько я понимаю, такой статистики, в общем-то, нет. Или у Вас она есть?
Re[7]: Ленивые языки - за и против
От: geniepro http://geniepro.livejournal.com/
Дата: 24.12.08 11:07
Оценка:
Здравствуйте, Qbit86, Вы писали:

Q>А как обстоят дела у Хаскеля с созданием GUI-приложений? Есть ли поддержка со стороны среды, библиотеки, фреймворки? Каковы принципиальные трудности?


Печально обстоят дела. Хаскелл ждёт своего вижуал-бейсика или дельфы...
Под линуксом ещё не так плохо, хотя биндинг к GTK+ постоянно запаздывает по сравнению с GHC.
Под виндою родной GUI-библиотеки нет, вручную на WinAPI делать неприятно и неудобно, да и не получилось у меня пока что-то дочтаточно заметное сделать...
Gtk2Hs требует GTK+, QtHaskell и wxHaskell как-то нетривиально устанавливаются, с полпинка у меня не получилось... Ужасно всё...
Re: Ленивые языки - за и против
От: mkizub Литва http://symade.tigris.org
Дата: 24.12.08 12:23
Оценка:
Здравствуйте, Gaperton, Вы писали:

G>Короче, я сторонник контроля над оружием, тьфу, явного управления ленивостью, посредством фьючерсов и стримов (ленивых списков), и строгости по умолчанию.


Каждый язык — это куча выборов (tradeoff) сделанных для удобства. И соответственно, удобнее эти языки применять там, где эти выборы подходят для решения задачи, и неудобно, где эти выборы не подходят.
Ленивость по умолчанию или явная — это то-же самое, что все остальные выборы.

ЗЫ Конечно SymADE Если ты можешь менять язык на котором программируешь — то конечно можно поменять и умолчания.
SOP & SymADE: http://symade.tigris.org , блог http://mkizub.livejournal.com
Re[5]: Ленивые языки - за и против
От: vshabanov http://vshabanov-ru.blogspot.com
Дата: 24.12.08 13:41
Оценка:
Здравствуйте, Gaperton, Вы писали:

G>>>Отвечу кратко. Пример с серией выражений, ссылающихся на результаты друг друга, делается в строгом по умолчанию языке с опциональной аннотацией ленивости элементарно. Аналогичный код в "строгом Хаскеле", с предлагаемой (примерной) аннотацией ленивости.


V>>Да собственно там, где в кемле появились ф-ии, возвращающие выражения, это и есть почти lazy annotation-ы (только не lazy, а просто ф-ии, т.к. вычисляются всегда строго один раз, многократно форсить не надо).


G>Не совсем. С ними, например, не должно получится кольцевую ссылку устроить. Вот так:


G>x = f1 a b y

G>y = f2 x a b

G>Это довольно типовой код в случае, если мы побили систему на набор функций, которые связанны ленивыми списками. Данный код — задает "коммутацию" схемы из функций, простым и понятным образом.


У меня не списки, а FRP-шные "поведения". Это поведение по сути машина Мили. data B a = B (simulation -> (a, B a)). Т.е. один такт (кадр) -- один вход (все внешние данные в simulation), один выход (a и следующая машина). Модель синхронная. Если сделать бесконечно вложенный x(y(x(y(...)))), то оно тупо упадет по stack overflow пытаясь выдать результат на текущем кадре. Чтобы не висло, можно сделать через switch -- переключалку на другое поведение по событию, не происходящему на текущем кадре.

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

G>Ни, и верятно, у этих функций довольно странный и неприятный тип. Что должно быть неудобно. Доступ к ленивости должен быть очень простой.


f1 :: a -> b -> [y] -> [x]
f2 :: [x] -> a -> b -> [y]

Вроде не очень странный.

V>>У меня например есть программист junior, который прогал только на Си и хаскеле. После хаскела ему тяжко объяснять, что тут из-за неленивости надо дополнительные фишки писать. При этом, когда он писал на хаскеле, единственной проблемой (неожиданностью), связанной с ленивостью, было закрытие файла до того, как он был обработан. Так что у всех разный опыт.


G>А этот junior сможет найти и устранить невычисленную цепочку, когда она появится? А вы — сможете? Вот thesz в свое время не смог.

G>http://thesz.livejournal.com/484854.html
G>

G>Время сборки мусора для копирующего сборщика (как в случае с ghc) пропорционально количеству живых данных. Если это количество все время растет (утечка), то время выполнения программы также начинает расти, причем квадратично — за время δT полезной работы мы добавляем δM байт к уже имевшимся ранее M байт и время работы сборщика становится t+δt. И в нашем случае так и было, причем формула зависимости времени работы для выполнения N команд процессора имела вид наподобие 0.0000001*N2+0.00016*N+0.7. Некоторое время на разогрев (ассемблирование и подготовка образа памяти), 6000 команд в секунду на старте и учет времени сборки утечки.

G>Большинство тестов укладывалось в 100000 тактов эмулируемого процессора (время ожидания более часа).

G>Где была утечка, я так и не нашел.


А фиг знает. Junior вряд-ли. Я -- не знаю, может получилось бы может нет. Там утечки, как я понял, были где-то в модели памяти, которую было почему-то тяжело было пофорсить. Может путем какого-то переписывания что-нить и получилось бы, вопрос времени.

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

Мне кажется, что борьба с утечками в рабочей программе всяко легче, чем попытки заставить программу работать вообще.

G>И наконец, разве junior-у не надо понимать, почему именно работает его программа? Если он это понимает, расстановка ленивости не вызовет у него проблем. И поможет потом читателю.


Надо понимать. Только надо понимать больше. Attention to irrelevant, т.е. работа уровнем ниже и производительность труда тоже ниже.

V>>В общем я остаюсь при мнении, что ленивость позволяет писать уровнем выше (не говоря уж о том, что у Хаскелла в принципе уровень выше).


G>Да, позволяет. Я с этим и не спорю. А еще она дает прикольные лики, если лениво все подряд.


Чтож поделать. trade-off. А в эрланге (если ничего не путаю) можно долго заниматься унификацией на больших структурах данных, или забить рантайм новосгенеренными атомами, или криво перегрузить модуль, да и вообще тупо напороться на ошибку типов в рантайме. "Но есть нюанс", есть свои плюсы, в определенных ситуациях перевешивают.

Я, как static typing fan, вообще не понимаю, как можно писать на эрланге что-то надежное (всегда улыбает надежность сколько-то девяток, должно быть 1.0), однако есть определенные подходы (тот же let it crash), при которых падение части программы не страшно (и применять их можно не только в эрланге).

Также и с ленивостью -- trade-off, иногда перевешивает, и так же есть свои подходы, можно обойти невычисленные цепочки, иногда просто (в серваках, где внешний мир форсит), иногда сложно (долго надо искать, да и то не удивлюсь, если через какой-нить profiling их таки можно вычислить), но опять-же иногда перевешивает.

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

awson, кстати, вполне себе написал небольшой сервер на HAppS & HSP. Ничего, работает уже несколько месяцев, хлеба(памяти) не просит. Он конечно нифига не сильно нагруженный (заказчикам сейчас не до него), но прецедент есть. И я не вижу особых причин, почему он должен ликать.

V>>Если же нужна большая уверенность в отсутствии невычисленных цепочек, и она нужнее скорости разработки, то чтож, надо использовать strict языки.


G>Ну да. Желательно — с "родной" опциональной ленивостью на уровне языка. Или хотя бы фьючерами.


В кемле есть опциональная ленивость. В последнем кемле можно даже в pattern matching-е писать lazy, чтобы самому не форсить. Только в таком виде оно не так удобно, как по-умолчанию.
Re[6]: Ленивые языки - за и против
От: vshabanov http://vshabanov-ru.blogspot.com
Дата: 24.12.08 13:49
Оценка:
Здравствуйте, Gaperton, Вы писали:

G>Здравствуйте, Аноним, Вы писали:


А>>Но, к сожалению, всё дискусия построенна на том, что Gaperton тупо игнорирует вопросы о подразумеваемой им области применения в которых он считает, что ленивость по-умолчанию не нужна. Про интенсивные вычисления и реал-тайм понятно, но опять же, cpu-hungry код выносится в либы и используется через FFI, а всю логику и описание control flow можно писать уже на другом языке.


G>Вся дискуссия, к сожалению, построена на том, что большинство участников за неимением ответов на вопрос Гапертона, тупо игнорируют его, пытаясь ему в ответ ему выливать все что угодно. Писал я про класс применений, если ты не заметил.


G>В больших программах на Хаскеле встречаются трудноуловимые утечки памяти, независимо от области применения. Чтоб нам было на эти проблемы плевать, "область применения" в результате не может являться:

G>1) Долгоработающим приложением. Все сервера 24х7 идут лесом в колонну по два. Все настольные аппликухи, которые могут долго работать — за ними.
G>2) Интерактивным приложением с софт-рилтайм гарантиями. Телеком, сетевые приложения, трейдинг, задачи управления и контроля идут лесом.
G>3) Приложением, которые работает в условиях ограниченных ресурсов. Embedded-разработка, обработка больших объемов данных — все лесом.

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

G>Остаются быстро работающие консольные аппликухи, которые не ограниченны памятью, и не жуют обчень больших данных. Только в данном классе приложений нам данная проблема не доставит проблем. Офигенный "класс приложений". Рекомендую.


А>>Именно поэтому что-то обьяснить ему не получится — так как всегда можно найти примеры, где ленивость не нужна (опять же, real-time приложения, интенсивные вычисления и т.п.). Вот так и получается, что раз "плоской" отвёрткой крутить шурупы с другим шлицом неудобно, то отвёртку нужно выбрость, потому что она больно не универсальная, и ещё нужно думать, какие отвёртки выбирать.


G>Объяснить ничего не получается, если не понимаешь, о чем идет разговор. Сочувствую. Я нигде не говорил, что "ленивость не нужна". Я говорил, что у полной ленивости по умолчанию есть проблемы. Это очень сложно понять? Очень сложно, блин, не заметить разницы между этими двумя тезисами?


Есть проблемы. Но мне они не кажутся такими страшными, чтобы не делать ленивость по-умолчанию. Ленивости бояться -- на хаскеле не писать )
Re[6]: Ленивые языки - за и против
От: thesz Россия http://thesz.livejournal.com
Дата: 24.12.08 14:16
Оценка: +1
G>В больших программах на Хаскеле встречаются трудноуловимые утечки памяти, независимо от области применения.

"Встречаются" — это просто песня.

Сейчас попробую развить...

Вот!

В больших программах на K встречаются опечатки вне зависимости от области применения.

Или.

В больших программах на C++ встречается всё, что угодно, я, однажды, гнома встретил. Тоже вне области применения.

Или вот:

В больших программах на C/C++/Фортране встречается сделанная на коленке, кривая и косая, медленная и полная багов половина реализации Common LISP, вне зависимости от области применения.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[7]: Ленивые языки - за и против
От: VladD2 Российская Империя www.nemerle.org
Дата: 24.12.08 15:36
Оценка:
Здравствуйте, vshabanov, Вы писали:

V>Не вижу тут ничего, что я бы не смог сделать на хаскеле. Возможно пришлось-бы потрахаться и поискать утечки, но результат был бы получен быстрее (по крайней мере мною), чем на Си (низкий уровень/неконтролируемый засер памяти) или erlang (динамическая типизация/низкий уровень, хотя говорят библиотеки с рантаймом хорошие).


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

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

И уж ленивость по умолчанию точно не даст тут ощутимых преимуществ.

V>Есть проблемы. Но мне они не кажутся такими страшными, чтобы не делать ленивость по-умолчанию. Ленивости бояться -- на хаскеле не писать )


Ну, лично для меня подобные проблемы ставят крест на Хаскеле как на инструменте. Еще одна проблема — отсутствие прикладных библиотек. Скажем Скала, Немерле или F# изначально живут поверх огромной библиотеки дотена или явы, что делает их отличными кандидатами для разработки под данные плаформы. Кроме того они отлично интегрируются с язками базовой платформы (ну, за исключением F#-а, который не очень здорово интегрируется) и позволяют расширять уже имеющиеся проекты.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: Ленивые языки - за и против
От: VladD2 Российская Империя www.nemerle.org
Дата: 24.12.08 15:37
Оценка:
Здравствуйте, thesz, Вы писали:

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


T>В больших программах на K встречаются опечатки вне зависимости от области применения.

T>...В больших программах на C/C++/Фортране встречается сделанная на коленке, кривая и косая, медленная и полная багов половина реализации Common LISP, вне зависимости от области применения.

Ну, может тогда взять Common LISP?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[8]: Ленивые языки - за и против
От: dr.Chaos Россия Украшения HandMade
Дата: 24.12.08 15:59
Оценка:
Здравствуйте, VladD2, Вы писали:

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


[оффтоп]
У хаскела с библиотеками всё нормально, их выбор, конечно, не так богат как у платформ Java/.Net, но библиотек хватает и довольно качественных.
[/оффтоп]
Побеждающий других — силен,
Побеждающий себя — Могущественен.
Лао Цзы
Re[11]: Ленивые языки - за и против
От: thesz Россия http://thesz.livejournal.com
Дата: 24.12.08 16:52
Оценка:
T>>Грубо говоря, если у тебя строгий map, то ты не можешь сделать его ленивым, просто пометив, если у тебя под рукой нет его текста.
G>Строгий или ленивый map — это не совсем корректно сказать. Смотри.
G>map( [ H | T ], F ) -> [ F( H ) | map( T, F ) ];
G>map( [], _ ) -> [].
G>Здесь у тебя два момента. Первое — ленивый или не ленивый у тебя конструктор списка. Это — одно. Второе — ленивое или энергичное у тебя вычисление функции F.

"Ленивый или не ленивый у тебя конструктор списка" по какому из аргументов?

Если по голове, то строгость функции F не важна, важна строгость map. Если только по хвосту, то это совсем другое дело.

G>Допустим, я хочу сделать применение F энергичным (сама F внутри может быть при этом ленивой) — это я пишу в коде map, а тип конструктора списка — таким же как конструктор списка-аргумента.


В результате ты реализуешь ленивый язык в полном его объёме.

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

Я просто не вижу других путей реализации описываемого тобой механизма.

G>Второе я могу сделать, сохранив общее полиморфное описание алгоритма. Так сделано в Clean, например.


Опять же, мои знания о компиляции ФЯП говорят, что это чрезвычайно затруднено.

Итак, у тебя в одном модуле создаётся список. Ленивый ли он, или нет, нам неизвестно. В другом модуле ты пишешь функцию ZeFunc с применением map к этому списку.

Тело map настолько сложно, что ты не можешь его разворачивать всюду, и анализ его затруднён.

Будет ли список после функции ZeFunc ленивым, или нет? Как это будет сделано?

Поясню.

На вход функции map приходит thunk, содержимое его неизвестно. Его надо форсировать (forced = eval thunk) и только тогда получится Cons (case forced of Cons x xs -> ... Nil -> ...).

Сам eval (условно) состоит из сравнения с образцом:

eval x = case x of
   -- Применения функций. Вызываем тела.
   ApplyF1 a1 a2 a3 a4 -> update x (bodyF1 a1 a2 a3 a4)
   ApplyMap f xs -> update x (bodyMap f xs)
   -- Уже форсированные значения. Вертаем взад.
   Cons _ _ -> x
   Nil _ -> x
   Int _ -> x


Но имея оный Cons мы ничего не знаем о том, какими были его аргументы — ленивыми или энергичными. Это тоже просто thunk-и, некоторые из которых уже значения, но они могли стать таковыми не при вычислении map или форсировании Cons.

Пример:
f a b = (x,x:[])
   where
      x = a+b


Если мы возьмём, да и проверим первый элемент пары на 0, то первый элемент списка тоже станет числом вместо (a+b). Стал ли наш Cons энергичным по голове?

T>> Форсировав чанк с отложенным map, ты обязательно вычислишь и голову, и хвост. Не уверен, что это хорошо. Точнее, уверен, что это плохо.

G>Если я напишу (назовем ленивое присваивание ?=) вот так
G>Res ?= map( Source, Fun )
G>И дам ему строгий список — то да. Если я дам ему аргументом ленивый список — то нет, даже если я выполню энергичное присваивание. Ты просто не задумываешься сейчас, в каких местах ленивость тебе действительно важна.

Мне достаточно того, что я не задумываюсь.

T>>Whole program analysis, получается, нужен.

T>>Получается, что аннотации ленивости дороги в сравнении.
G>Не вижу, как это получается. Ты пример приводить будешь в качестве иллюстрации? Спрашиваю уже раз в пятый.

Чуть выше ты привёл примеров на троих, вместе взятых. Хотя я добавил.

Вкратце: аннотация ленивости должна проходить через весь путь возможного прохождения ленивого значения.

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

Сравни: мне надо вставить аннотацию энергичности ровно в те места, где мне надо форсировать значения раньше времени.

Что мне надо сделать, чтобы map стал не ленивым по хвосту в нужном мне месте?
   strictList [] = []
   strictList (x:xs) = (x:) $! strictList xs
   map' f xs = strictList $ map f xs
-- *Main> take 3 $ map' (+1) ([1,2,3,error "bbb",5]++error "aaa")
-- Exception: aaa
-- Полностью ленивый map:
-- *Main> take 3 $ map (+1) ([1,2,3,error "bbb",5]++error "aaa")
-- [2,3,4]


По голове?
   strictList' [] = []
   strictList' (x:xs) = ((:) $! x) $ strictList' xs
   map'' f xs = strictList' $ map f xs
-- *Main> head $ drop 4 $ map'' (+1) ([1,2,3,error "bbb",5]++error "aaa")
-- *** Exception: bbb
-- Полностью ленивый map:
-- *Main> head $ drop 4 $ map (+1) ([1,2,3,error "bbb",5]++error "aaa")
-- 6


По хвосту и голове получается комбинированием.

Вуаля!

Такое форсирование надо провести только в местах скопления вычислений. Библиотечные функции править не надо.

Да и то, оно обычно вредит.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[8]: Ленивые языки - за и против
От: thesz Россия http://thesz.livejournal.com
Дата: 24.12.08 16:55
Оценка:
T>>...В больших программах на C/C++/Фортране встречается сделанная на коленке, кривая и косая, медленная и полная багов половина реализации Common LISP, вне зависимости от области применения.

VD>Ну, может тогда взять Common LISP?


Гринспуна ты, конечно, не читал.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.