LINUX.ORG.RU

Haskell vs Lisp


1

0
Не знаю вообще ни одного функционального языка. С какого легче начать обучение - Haskell или Lisp. И, если Lisp, то какой самый распространенный интерпретатор?
anonymous
Ответ на: комментарий от Miguel
>> Да не zip, а зиппер. Вот тебе для списков, для деревьев сделаешь сам:

Это ничем не отличается от вставки элемента в голову списка типа x:xs. Естественно вставка влево-вправо это O(1), а если мне надо вставить не на соседнюю поицию, а через несколько? Рекурсивно применять toRight/toLeft? И где тут O(1)? Тут скорее O(n)где n-число позиций между текущей и той куда надо вставить. Прежде чем вставить элемент, мне надо сначала добраться до нужной позиции путем последовательного прохода по спику, так?. Другого способа добраться до нужной мне позиции нет.

cathode ★
()
Ответ на: комментарий от Miguel
>> Вспоминай человеческий язык.

Это был пример той самой многозначности :))

cathode ★
()
Ответ на: комментарий от cathode
> Прежде чем вставить элемент, мне надо сначала добраться до нужной позиции путем последовательного прохода по спику, так?

А зачем тебе вставлять элемент в позицию, которой ты в глаза не видел?

Список (вар.: дерево) - это корневой каталог и абсолютные пути; зиппер - это текущий каталог, команда cd, и относительные пути.

Miguel ★★★★★
()
Ответ на: комментарий от Miguel
>> А зачем тебе вставлять элемент в позицию, которой ты в глаза не видел?

Ну приехали...

У меня есть список [1 2 3 4 5 6], мне надо 6 поменять на 10, текущая позиция на двойке, и как мне это сделать без 4-х кратного применения toRight?

>> это корневой каталог и абсолютные пути; зиппер - это текущий каталог, команда cd, и относительные пути

Можно и без аналогии, тем более что она неправильная т.к. cd может перебросить меня в любую каталог файловой системы за одну комманду, а Zipper не может передвинуть меня дальше одной позиции за раз.

cathode ★
()
Ответ на: комментарий от cathode
> У меня есть список [1 2 3 4 5 6], мне надо 6 поменять на 10, текущая позиция на двойке, и как мне это сделать без 4-х кратного применения toRight?

Ещё раз: это тебе святой дух нашептал, что надо именно 6-ю позицию поменять?

> cd может перебросить меня в любую каталог файловой системы за одну комманду, а Zipper не может передвинуть меня дальше одной позиции за раз.

Ну, блин, приехали.

multipleRight :: Integer -> Zipper a -> Zipper a

multipleRight 0 = id

multipleRight n = multipleRight (n-1) . toRight

Miguel ★★★★★
()
Ответ на: комментарий от Miguel
>> Ещё раз: это тебе святой дух нашептал, что надо именно 6-ю позицию
 поменять?

Miguel хватит тупить а?  Мне надо получить доступ к  i-му элементу 
массива за O(1), что тут непонятно? Или тебе трудно представить задачу 
где это необходимо? 

>> multipleRight n = multipleRight (n-1) . toRight

Пацтулом. и ты мне хочешь сказать, что это O(1)? 
Ну давай посмотрим, что будет при n=3, раз ты сам не можешь.

multipleRight 3
multipleRight 2 . toRight
multipleRight 1 . toRight . toRight
toRight . toRight . toRight

Итого имеем три отложенных вызова toRight  и 3 рекурсивных вызова 
miltipleRight, т.е. сложность алгоритма по использованной памяти O(n),
 по времени тоже O(n).

Нельзя реализовать доступ к массиву за О(1) операцями типа x:xs и 
подобными, неужели это не понятно?


cathode ★
()
Ответ на: комментарий от cathode
>и как мне это сделать без 4-х кратного применения toRight?

Да никак! Это же список! Если тебе критичен доступ к _произвольному_ элементу со сложностью O(1) используй массив.

Macil ★★★★★
()
Ответ на: комментарий от cathode
> Пацтулом. и ты мне хочешь сказать, что это O(1)?

Дурень, ты хочешь сказать, что cd работает за O(1) от длины пути?

> Нельзя реализовать доступ к массиву за О(1) операцями типа x:xs и подобными, неужели это не понятно?

Да мне-то понятно, но неужели ты думаешь, что операциями типа car и cdr это возможно?

Miguel ★★★★★
()
Ответ на: комментарий от Miguel
> Тогда так и говори: не "все функции", а "все функции стандартной библиотеки". А вот в хаскеле - именно ВСЕ.

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

Burbaka ★★
()
Ответ на: комментарий от Miguel
Позиция тебе может быть известна и предварительно. Когда создавал дерево ты позицию запомнил, а потом в процессе дальнейших вычислений выяснилось, что какое-то значение в этой позиции надо поменять.
Burbaka ★★
()
Ответ на: комментарий от Miguel
Угу. Вместо того чтобы пользоваться простой структурой данных приходится изобретать вот такие врапперы.
Burbaka ★★
()
Ответ на: комментарий от Macil
>> Да никак! Это же список! Если тебе критичен доступ к _произвольному_ элементу со сложностью O(1) используй массив.

Замечтально... Теперь покажи мне это в Хаскеле. И что-то мне подсказывает, что сделано это далеко не в чисто функциональном стиле, ага. Через unsafeWrite со всеми вытекающими.

cathode ★
()
Ответ на: комментарий от cathode
Я бы даже пример поправил. Имеется список [1 2 3 4 5 6 ... 100]. В данном списке заранее известны определенные элементы, которые попадают в группу "риска" и в дальнейшем могут поменяться. Ну например, 2,6,40,55,70,78 ... и т.д. По ходу вычислений выяснилось что необходимо поменять значения элементам 2,40,78, ... Тот зипер, который ты описал ( как я его понял) за 0(1) эту задачу решить не позволит. Первый элемент мы допустим поменяем за 0(1), а до других надо будет добираться через toLeft и toRight. Следовательно надо прудумывать какую-то другую структуру данных
Burbaka ★★
()
Ответ на: комментарий от Miguel
>> Да мне-то понятно, но неужели ты думаешь, что операциями типа car и cdr это возможно?

Нет, для этого есть vector-set!

cathode ★
()
Ответ на: комментарий от imp
> А зачем тогда ФП язык использовать?

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

Лично я за идею о языке - комбайне который включает в себя и ФП и ООП и СП и т.д. При этом скорее всего потеряется столь любимая хаскелистами ленивость... ну и фиг с ней с другой стороны.

Burbaka ★★
()
Ответ на: комментарий от Burbaka
> Лично я за идею о языке - комбайне который включает в себя и ФП и ООП и СП и т.д. При этом скорее всего потеряется столь любимая хаскелистами ленивость... ну и фиг с ней с другой стороны.

Написал бы проще: "Лично я - за OCaml".

anonymous
()
Ответ на: комментарий от Miguel
>> Дурень, ты хочешь сказать, что cd работает за O(1) от длины пути?

Если по каталогам построить индекс то таки да.

cathode ★
()
Ответ на: комментарий от cathode
>Теперь покажи мне это в Хаскеле

Data.Array (IArray, MArray), Data.ByteString

>И что-то мне подсказывает, что сделано это далеко не в чисто функциональном стиле, ага.

Тебе шашечки или ехать? Ну да, произвольный тип в Array ты запихивать не сможешь. Только указатель. Да, там есть различные unsafe* функции, которые выполняются быстрее. Да с массивами сложно работать. Да IO вносит свой оверхед.

MArray монадический, это "чистый функциональный стиль"?

А где-ты видел массивы, сделанные в чисто функциональном стиле? Лисп, Схема, OCaml, на чистые ФП языки не тянут.

Macil ★★★★★
()
Ответ на: комментарий от Macil
> А где-ты видел массивы, сделанные в чисто функциональном стиле? Лисп, Схема, OCaml, на чистые ФП языки не тянут.

Звучит как "Девчонки, а вам когда-нибудь яйца дверью прищемляли?" Мне пофигу, в каком оно стиле, мне надо чтобы удобно и эффективно.

anonymous
()
Ответ на: комментарий от Macil
>> Data.Array (IArray, MArray), Data.ByteString

Вот о них я и писал.

>> Тебе шашечки или ехать? Ну да, произвольный тип в Array ты запихивать не сможешь. Только указатель. Да, там есть различные unsafe* функции, которые выполняются быстрее. Да с массивами сложно работать. Да IO вносит свой оверхед.

Вот и нафига это надо если есть куда более простые способы?

>> А где-ты видел массивы, сделанные в чисто функциональном стиле? Лисп, Схема, OCaml, на чистые ФП языки не тянут.

Нигде. Потому что чистый ФЯ - это абсурд.

>> MArray монадический, это "чистый функциональный стиль"?

Кстати мне всегда было интересно вот что: если монада (тот же MArray) реализована исключительно на Хаскеле функциями, часть из которых не имеет функциональной чистоты (unsafeWrite, unsafeRead), то почему этот язык называется "чистым функциональным языком"?

cathode ★
()
Ответ на: комментарий от anonymous
>Мне пофигу, в каком оно стиле, мне надо чтобы удобно и эффективно.

Дык юзай списки, удобно и эффективно. А массивы в _общем_ случае это не удобно. То что называется массивами в С не есть массивы, а есть обычная арифметика с указателями. В C++ работа с массивами организована ИМХО лучше всех, правда STL тоже критерию "удобно" не соответствует.

Macil ★★★★★
()
Ответ на: комментарий от Burbaka
> Кстати следуюя предварительным, чисто поверхностным соображениям, без заглядывания во внутрь хитроумных схемовских конструкций, транслятор может выявлять функции в которых возможны сайд эффекты-автоматически

???

И что он с ними будет делать?

Miguel ★★★★★
()
Ответ на: комментарий от Burbaka
> Позиция тебе может быть известна и предварительно. Когда создавал дерево ты позицию запомнил, а потом в процессе дальнейших вычислений выяснилось, что какое-то значение в этой позиции надо поменять.

Да ёклмн, не проблема это. Список точно также можно взять не за одну позицию, а за две или сколько надо. Структура станет не сильно сложнее.

Miguel ★★★★★
()
Ответ на: комментарий от cathode
>Вот и нафига это надо если есть куда более простые способы?

Дык тебя насильно заставляют? Опять же ты столкнулся с задачей когда списки работали неэффективно? Или ты просто теоретизируешь?

>Потому что чистый ФЯ - это абсурд.

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

>часть из которых не имеет функциональной чистоты (unsafeWrite, unsafeRead), то почему этот язык называется "чистым функциональным языком"?

Еще про функцию trace забыл. А сколько "грязных хаков" в любой операционке? Или даже в более-менее сложной программе? Если ты используешь unsafe* функции, так это лично твои проблемы. Опять же никто с тебя не требует их использовать, но "срезать угол" возможно.

MArray это не монада, это Mutable Array. Для разрешения заморочек c "внешним миром" используется IO.

Macil ★★★★★
()
Ответ на: комментарий от Burbaka
Да там нечего особо придумывать. Каждому элементу даём не только следующий за ним (как в обычном списке), но и следующий "рискованный". Ну и оборачиваем это дело зиппером. Проблемы нет.

Кстати: со СПИСКОМ ни один язык не будет работать за O(1). Вообще. Нужно O(1) - юзайте массив.

Miguel ★★★★★
()
Ответ на: комментарий от cathode
И он, конечно, тебе в списке сделает что надо за O(1).
Miguel ★★★★★
()
Ответ на: комментарий от Miguel
> Да там нечего особо придумывать. Каждому элементу даём не только следующий за ним (как в обычном списке), но и следующий "рискованный".

Все равно получаем, что все надо обойти "рискованные" элементы от текущего подлежащего замене, до следующего и т.д. Если в группе риска элементов много, а на деле меняются единицы, то получаем сложность O(M),где M - размер группы риска, а хотелось бы O(L), где L - количество меняющихся на самом деле элементов.

> Кстати: со СПИСКОМ ни один язык не будет работать за O(1). Вообще. Нужно O(1) - юзайте массив.

Смотря что делать. Если надо удалить L заранее выбранных элементов списка то можно за O(L), т.е. для одного элемента будет сложность O(1)

Burbaka ★★
()
Ответ на: комментарий от cathode
Data.Array.ST

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

Если хочется чистого ФП:

Data.Sequence

update :: Int -> a -> Seq a -> Seq a

O(log(min(i,n-i))). Replace the element at the specified position

imp ★★
()
Ответ на: комментарий от Miguel
> ??? > И что он с ними будет делать?

Всмысле "что". Будет передавать эту информацию программисту-функциональщику, который любит чтобы в функциях не было сайд-эфектов. Типа: в этих функциях возможны сайд-эфекты, будь осторожен, а в этих все чисто. При наличии Lisp-овского REPL-а такой функционал будет достаточно легко интегрировать в среду разработки. Более того скорее всего нормальные трансляторы такой анализ функций выполняют при оптимизации, для вычисления инвариантных фрагментов в циклических конструкциях

Burbaka ★★
()
Ответ на: комментарий от Burbaka
> Если надо удалить L заранее выбранных элементов списка то можно за O(L)

Если есть заранее выбранные элементы, можно и на Хаскеле сделать за O(L).

Miguel ★★★★★
()
Ответ на: комментарий от Burbaka
> Будет передавать эту информацию программисту-функциональщику, который любит чтобы в функциях не было сайд-эфектов.

А фигли тогда не следить за чистотой самому?

Miguel ★★★★★
()
Ответ на: комментарий от Miguel
> Если есть заранее выбранные элементы, можно и на Хаскеле сделать за O(L).

Расскажи, действительно любопытно. Для общего развития

Burbaka ★★
()
Ответ на: комментарий от Miguel
> А фигли тогда не следить за чистотой самому?

Во первых, не всё ты пишешь сам, а во вторых ингода сайд-эфекты удобны.

Burbaka ★★
()
Ответ на: комментарий от Burbaka
>> А фигли тогда не следить за чистотой самому?

> Во первых, не всё ты пишешь сам,

Я имел в виду транслятор. Почему бы ему самому не следить за чистотой и не давать ерроры вместо "информации для программиста"?

Miguel ★★★★★
()
Ответ на: комментарий от Burbaka
> Расскажи, действительно любопытно.

Дык уже рассказал. Дополнительно к следующему элементу указывать на следующий выбранный.

Miguel ★★★★★
()
Ответ на: комментарий от Miguel
Тогда уж лучше тупо выкинуть из языка все конструкции которые дауют побочные эфекты и все. Получим что-то местами похожее на хаскель. Только не выплеснем ли мы при этом вместе с водой ребенка ?
Burbaka ★★
()
Ответ на: комментарий от Miguel
Чето не могу представить как это в коде будет. Покажи. Схематично хотябы
Burbaka ★★
()
Ответ на: комментарий от Macil
>> Еще про функцию trace забыл. А сколько "грязных хаков" в любой операционке? Или даже в более-менее сложной программе? Если ты используешь unsafe* функции, так это лично твои проблемы. Опять же никто с тебя не требует их использовать, но "срезать угол" возможно.

При чем здесь грязные хаки в операционках? При чем здесь личные проблемы? Речь идет о производительности алгоритмов, да и грязные хаки, как ты выразился - понятие относительное. С точки зрения ФП qsort выполненный на С - грязный хак, и что? Объясни мне теперь, что код на хаскеле работающий в разы медленнее сишного варианта, но зато дико красивый, лучше чем грязный хак на С.

>> Ну, ну. Изучать его сложно, а затем видны реальные выгоды такого подхода.

Выгода там одна - уровень абстракции, которая убивается напрочь эффективностью полученных программ.

>> Дык тебя насильно заставляют? Опять же ты столкнулся с задачей когда списки работали неэффективно? Или ты просто теоретизируешь?

Меня насильно никто не заставляет, поэтому хаскелем я не пользуюсь ;)

cathode ★
()
Ответ на: комментарий от imp
>> Data.Array.ST ... и далее по тексту...

Я промолчу, что само это написано, как тут было сказано, "грязными хаками", на чистом как слеза функциональном языке. Ну-ну

>> Если хочется чистого ФП: Data.Sequence update :: Int -> a -> Seq a -> Seq a O(log(min(i,n-i))). Replace the element at the specified position

Мне надо O(1), нафиг мне Data.Sequence который это не умеет?

cathode ★
()
Ответ на: комментарий от cathode
>Речь идет о производительности алгоритмов

Еще раз спрашиваю, ты реально уперся в ограничения хаскеля или просто теоретизируешь?

>Выгода там одна - уровень абстракции, которая убивается напрочь эффективностью полученных программ.

>Объясни мне теперь, что код на хаскеле работающий в разы медленнее сишного варианта, но зато дико красивый, лучше чем грязный хак на С.

>Выгода там одна - уровень абстракции, которая убивается напрочь эффективностью полученных программ.

Вот ты и сам ответил чем лучше.

А что ты хотел? На ежа сесть и не уколоться? Не бывает такого в природе. У хаскеля очень высокий уровень реюзабельности. Он в конечном счете более понятен и намного более прост в использовании, чем, скажем, ява/С++. Да и мощным матаппаратом он подкреплен в отличие от...

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

Macil ★★★★★
()
Ответ на: комментарий от cathode
>Дык уже ж показали ни эффективно

Код на С зато небезопасен. Если ты сможешь программу на 100000 строк на С вылизать да такого уровня до какого вылизан sort в С, то такой код тебе на вес золота обойдется учитывая трудозатраты. А так все время будешь за пределы массивов выходить и по невалидным указателям обращатся. Так что нафиг такую эффективность.

imp ★★
()
Ответ на: комментарий от Macil
>> Еще раз спрашиваю, ты реально уперся в ограничения хаскеля или просто теоретизируешь?

Ну если это можно назвать "реально", то да - сравнивал qsort на Хаскеле, которым весь инет забит с сишным вариантом. Чтобы засечь разницу в скорости не понадобилась даже секундная стрелка на часах :))

>> А что ты хотел? На ежа сесть и не уколоться?

Нет, просто меня нервирует тот факт, что haskell fanboys пытаются им все дыры заткнуть.

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

Прям шаолинь какой-то :)) Это не экзамен - это психологическая потребность спросить у других "зря ли я потратил год?". Ну и вопрос про цену, на самом деле больше тебя волнует чем меня :)

cathode ★
()
Ответ на: комментарий от cathode
>Ну если это можно назвать "реально", то да - сравнивал qsort на Хаскеле, которым весь инет забит с сишным вариантом. Чтобы засечь разницу в скорости не понадобилась даже секундная стрелка на часах :))

Ага я тоже сравнивал random 1000000 Int из файла - mergesort из Data.List.sort 5.5 s, qsort на MArray 1.0 s, C - 0.38 s

Зато если тебе не нужны все данные, а например только некоторые вначале то картина будет совсем другая, а если тебе нужны все, то зачем тогда ленивость? Ты жертвуешь тут зато можешь получить глобальное преимущество за счет ленивости, опять же это будет заметно только в большой нетривиальной задаче.

imp ★★
()
Ответ на: комментарий от cathode
>Нет, просто меня нервирует тот факт, что haskell fanboys пытаются им все дыры заткнуть.

Фанатегов нужно игнорировать, нервные клетки не восстанавливаются.

>то да - сравнивал qsort на Хаскеле, которым весь инет забит с сишным вариантом.

И больше ничего? Значит теоретизируешь. Попробуй на хаскеле сделать парсер какого-нибудь текстового файла, а еще лучше XML'а с помощью HXT. Сразу возникнет ощущение, что чего-то важное в жизни ты пропустил.

>Прям шаолинь какой-то

А ты как думал. Потребности спросить, потратил ли я год зря не возникает: ФП позволяет взглянуть на обычные проблемы под другим углом. А самая главная проблема в изучении хаскеля - недостаток математических знаний. А другая проблема в том, что годами наработанные "императивные" идиомы, либо вообще не работают, либо очень вредят.

Macil ★★★★★
()
Ответ на: комментарий от imp
> Ты жертвуешь тут зато можешь получить глобальное преимущество за счет ленивости, опять же это будет заметно только в большой нетривиальной задаче...

...а память нынче дешёвая.

anonymous
()
Ответ на: комментарий от Macil
> Попробуй на хаскеле сделать парсер какого-нибудь текстового файла, а еще лучше XML'а с помощью HXT. Сразу возникнет ощущение, что чего-то важное в жизни ты пропустил.

Уж лучше на OCaml сделаю, лол.

anonymous
()
Ответ на: комментарий от cathode
Да и вот еще - попробуй так, у меня вышло заметно быстрее

part [] = ([],[],[])
part (x:xs) = partition' xs [] [x] []

partition' [] less eq more = (less, eq, more)
partition' (x:xs) less eq@(p:_) more = case compare x p of
                                            LT -> partition' xs (x:less) eq more
                                            EQ -> partition' xs less (eq++[x]) more
                                            GT -> partition' xs less eq (x:more)

qsort [] = []
qsort x = qsort less ++ eq ++ qsort more 
  where
  (less, eq, more) = part x
imp ★★
()
Вы не можете добавлять комментарии в эту тему: топик перемещен в архив.