LINUX.ORG.RU

Haskell vs Lisp


1

0

Не знаю вообще ни одного функционального языка. С какого легче начать обучение - Haskell или Lisp. И, если Lisp, то какой самый распространенный интерпретатор?

anonymous

Ответ на: комментарий от cathode

>Если это про pattern matching, то если ты не заметил лисповый вариант куда мощьнее хаскелльного. Например ты можешь в хаскелле сматчить s-expression?

Именно сматчить легко, а если ты потом еще хочешь с ним работать как с кодом то тогда надо Template Haskell поюзать... Ниче там не мощнее - lazy matching же не сделаешь... Вот так оно может?

let a@((Just x):_) = [Just 5, Nothing]

a = [Just 5, Nothing] x = 5

imp ★★
()
Ответ на: комментарий от cathode

>Таки да. Это даже быдложава умеет

А почему бы такую простую и полезную вещь не сделать искаропки?

imp ★★
()
Ответ на: комментарий от imp

> Trees. A tree is an example of a recursive datatype.

Список в Лиспе - основная конструкция (ну и cons)

> По мне так это велосипедизм, вместо одной стандартной реализации - зоопарк костылей... А библиотек можно и в Haskell'е наплодить...

И библиотеки будут расширять язык? Порождая зоопарк костылей вместо одной стандартной реализации?

mv ★★★★★
()
Ответ на: комментарий от imp

> А почему бы такую простую и полезную вещь не сделать искаропки?

Загромождая язык?

mv ★★★★★
()
Ответ на: комментарий от imp

>> По мне так это велосипедизм, вместо одной стандартной реализации - зоопарк костылей... А библиотек можно и в Haskell'е наплодить...

В хаскелле тоже не одна реализация - это раз. Во вторых диалектов лиспа дофига и если говорить о стандарте без зоопарка то Common Lisp тебе в руки. Там стандартизовано (именно стандартизовано, ANSI и все такое) столько, что Хаскелю и не снилось. В третьих все что реализовано в "стандартной реализации" GHC (которая далеко не стандартная а зоопарк расширений) - это тоже набор костылей к Haskell 98. Так что не надо грязи.

cathode
()
Ответ на: комментарий от imp

>> то тогда надо Template Haskell поюзать

А это конечно же не костыль?

>> let a@((Just x):_) = [Just 5, Nothing]

Всего с шестью скобками нет :) Надо скобок 20-30, доволен? :))

cathode
()
Ответ на: комментарий от mv

>> Список в Лиспе - основная конструкция (ну и cons)

Список (list) это синтаксический сахар для cons:

(list 1 2 3) -> (cons 1 (cons 2 (cons 3 nil)))

cathode
()
Ответ на: комментарий от cathode

Я это и хотел сказать, только коряво :)

mv ★★★★★
()
Ответ на: комментарий от cathode

cons непричем, Списки и деревья это примеры рекурсивных типов,
но есть и другие, вот например из "Write Yourself a Scheme in 48 Hours":

data LispVal = Atom String
| List [LispVal]
| DottedList [LispVal] LispVal
| Number Numb
| String String
| Bool Bool
| Port Handle
| PrimitiveFunc ([LispVal] -> ThrowsError LispVal)
| IOFunc ([LispVal] -> IOThrowsError LispVal)
| Func {params :: [String], vararg :: (Maybe String),
body :: [LispVal], closure :: Env}

imp ★★
()
Ответ на: комментарий от imp

> Списки и деревья это примеры рекурсивных типов, но есть и другие,

Т.е. вопрос наличия рекурсивных типов в Лиспе с повестки дня снят?

mv ★★★★★
()
Ответ на: комментарий от mv

>Т.е. вопрос наличия рекурсивных типов в Лиспе с повестки дня снят?

Нет, вопрос был не в наличии, а в обьявлении собственных. Списки и деревья через cons - это не то...

imp ★★
()
Ответ на: комментарий от imp

> Нет, вопрос был не в наличии, а в обьявлении собственных. Списки и деревья через cons - это не то...

Чем не то?

mv ★★★★★
()
Ответ на: комментарий от imp

>> Списки и деревья это примеры рекурсивных типов, но есть и другие

imp, если своими словами, то тип можно построить при помощи двух операций: неперсекающегося объединения и декартова произведения. Например, новый тип из двух других можно создать так A U (B X A), что эквивалентно хаскельному:

data Type1 A B = A | Type1Cons B A

точно такой же тип можно и теми же операциями (U и X) можно создать в лиспе. Далее, используя эти две операции можно создать сколь угодно сложный составной тип из набора ранее определенных типов. ЭТО АЗБУКА. И это можно сделать в любом языке!!!!, а не только в Хаскеле.

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

(define (cons x y) (lambda (m) (m x y)))

(define (car z) (z (lambda (p q) p)))

Отличие здесь в том, что в хаскеле есть для этого специальный синтаксис в виде data и отличное пространство имен, а в лиспе нет, хотя по сути, из моего примера с Type1, "Type1Cons" - это конструктор ничем не отличающийся от cons. И самое главное, если в лиспе нет специального синтаксиса для чего-то, то это не значит, что его нельзя создать (не путать, например, с упомянутым ранее монадическим '>=' - это всего лишь инфиксная форма функции) - лисп в отличие от хаскеля здесь просто выигрывает, и тогда весь синтаксический сахар (а data это именно он, т.к. по сути это специальная форма для определения лямбда-абстракций) хаскеля ни чего не доказывает. Лисп - расширяемый язык, хаскель - нет.

ЗЫ про Template Haskell я в курсе, но это уже как раз набор нестандартных костылей в отличие от лиспа :)))

cathode
()
Ответ на: комментарий от imp

>> Списки и деревья через cons - это не то...

Мля, ну посмотри ты хоть раз в Prelude или учебник по хаскелю!!! Как там определен список? А? (Hint замени ':' на cons)

cathode
()
Ответ на: комментарий от cathode

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

Ключевое слово _ранее определенных_. Опять же это хорошо когда просто типы, и другое когда типы с параметрами. Опять же в определении

data Maybe a = Just a | Nothing

Никакой из упомянутых типов не был определен ранее.

>Лисп - расширяемый язык, хаскель - нет.

Ага - скажи это авторам расширений для GHC... Пользовательские операторы и типы без всяких Template Haskell'ев определяются - чаще всего этого достаточно. Просто Лисп сам примитивен и имеет мало синтаксического сахара, поэтому есть макросы для добавления "сахара по вкусу". В хаскелле же наоборот дофига сахара (причем хорошего, универсального и хорошо ложащегося на парадигму) поэтому желание добавить что то возникает реже.

Подведя итог - Лисп более универсален, но для применения в какой то области требует заточки обычно в виде превращения его в DSL. А haskell уже DSL для ФП со всеми плюсами и минусами, поэтому для задач хорошо ложащихся на ФП Хаскелл круче лиспа, так же как на лиспе проще в не ФП стиле писать...

imp ★★
()

В Haskell очень красиво выглядят фундаментальные алгоритмы. Вот например КМП:

data KMP a = KMP { kmpDone :: Bool, kmpNext :: (a -> KMP a) }

isSubstringOf :: (Eq a) => [a] -> [a] -> Bool
isSubstringOf w s = match (makeTable w) s
where match table [] = kmpDone table
match table (x:xs) = kmpDone table || match (kmpNext table x) xs

makeTable :: (Eq a) => [a] -> KMP a
makeTable xs = table
where table = makeTable' xs (const table)
makeTable' [] failure = KMP True failure
makeTable' (x:xs) failure = KMP False test
where test c = if c == x then success else failure c
success = makeTable' xs (kmpNext (failure x))

wieker ★★
()
Ответ на: комментарий от fmj

> С чего многоувожаемый ЛОР аналитик сделал такие далеко идущие выводы? Во первых Haskell куда более точно отражает ФП парадигму, а это дает ему право заставлять приспосабливатся к нему

К кому? Вот именно, не все задачи решаются в функциональном стиле (просто и эффективно), хаскель же предлагает использовать для решения этих задач костыли. А приспосабливаться он не может к окружающей среде. которая требует и функциональные и императивные инструменты. Основное же достоинство лиспа, как говорил Брюс Ли:

`Будь водой, если воду налить в стакан -- она примет форму стакана, если налить в кувшин -- она примет форму кувшина...'

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

// :(

anonymous
()
Ответ на: комментарий от anonymous

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

fmj
()
Ответ на: комментарий от imp

>> Ключевое слово _ранее определенных_. Опять же это хорошо когда просто типы, и другое когда типы с параметрами. Опять же в определении

>> data Maybe a = Just a | Nothing

>> Никакой из упомянутых типов не был определен ранее.

Just a и Nothing - это не типы а КОНСТРУТКОРЫ!!!! Тип здесь Maybe a. Ты внимательно читал, что я написал? Здесь ты создаешь при помощи конструкторов тип Maybe a из a. Тип a уже определен ранее - это любой наперед заданный тип или, что тоже самое, любой определенный ранее или позднее (полиморфность, мать ее:)). Кроме этого следует разделять описание типа и его реализацию. Когда ты пишешь data = ... у тебя есть только описание типа, но нет данных. Когда ты напишешь функцию, принимающую "a" и возвращающую "Maybe a" (т.е. _реализуешь_ конструктор) ты реализуешь тип. Для лиспа описание типов данных не требуется в нем описание и реализация "склеены воедино". Для хаскеля описание типов тоже не требуется, кстати. Ты можешь работать с деревьями и списками не имея описания в виде data :)))

>> Пользовательские операторы и типы без всяких Template Haskell'ев определяются - чаще всего этого достаточно.

Пользовательский оператор - это специальная форма для функции. При том синтаксис всегда один и тот же, например для +: a + b или (+) a b. Вот что там стоит вместо плюс ты можешь напрограммить сам, а вот изменить синтаксис выражения ты не можешь, тут и вылазит мощь лиспа :))). Ну а создание типов данных есть во всех языках даже в C :)))

>> Подведя итог - Лисп более универсален, но для применения в какой то области требует заточки обычно в виде превращения его в DSL. А haskell уже DSL для ФП со всеми плюсами и минусами, поэтому для задач хорошо ложащихся на ФП Хаскелл круче лиспа, так же как на лиспе проще в не ФП стиле писать...

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

((захавать ртом) ((приготовить хавчик) макароны тушенка)))

Вот ФП это или нет? :)))

cathode
()
Ответ на: комментарий от fmj

> Ну конечно не быть хаскелю mainstream-ом

Он пока не перешел даже в разряд малоиспользуемых языков, как Lisp, например, какой уж тут мейнстрим...

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

Боюсь, если добавлять императивные возможности, он превратиться в сборище костылей и подпорок и вся его `красота и чистота' (мне не нравиться его синтаксис) улетучиться.

// :(

anonymous
()
Ответ на: комментарий от anonymous

> К кому? Вот именно, не все задачи решаются в функциональном стиле (просто и эффективно), хаскель же предлагает использовать для решения этих задач костыли. А приспосабливаться он не может к окружающей среде. которая требует и функциональные и императивные инструменты.

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

imp ★★
()
Ответ на: комментарий от anonymous

>Ну конечно не быть хаскелю mainstream-ом

Да вряд ли, скорее Ocaml под видом F#. Ну и ладно - я не комплексую что Haskell мало используют. Зато по делу.

imp ★★
()
Ответ на: комментарий от imp

> усложняется распаралелливание

Вот я слышал что Erlang -- Concurrent Jedi, а вот чтобы Haskell со своими убогими компиляторами/интерпритаторами хватал звезды... это что-то из области фантастики. Все эти мегавозможности, большей частью, красивы и мощны только на словах и учебных примерах, а вот как до реальных проектов дело доходит, так сразу появляются костылики. А функционалность -- это конечно хорошо, но хорошо в меру и серебряной пулей не является. Water-like Lisp -- наше все :)

// :(

anonymous
()
Ответ на: комментарий от imp

> Ну и ладно - я не комплексую что Haskell мало используют. Зато по делу.

По какому делу? Писать учебные примеры и факториалы/фибоначи?

// :(

anonymous
()
Ответ на: комментарий от imp

вот я читаю и думаю... какой баян :)

ocaml это умеет с чертикогда :)

Rastafarra ★★★★
()
Ответ на: комментарий от cathode

> Для хаскеля описание типов тоже не требуется, кстати. Ты можешь работать с деревьями и списками не имея описания в виде data :)))

Думаешь я этого не знал?

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

Ну почему, я могу определить префиксный, инфиксный и постфиксный оператор. А еще есть (.) и flip чтобы эффективно писать. А другие извращения с синтаксисом которые вы у себя в Лиспе вытворяете - суть есть изврат и есть более прямые способы добиваться того же...

imp ★★
()

Зависит от твоего опыта. Я, например, до изучения фп работал в основном со статически типизированными языками, поэтому мне проще было начать с Caml-а и Haskell-а.

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

> Just a и Nothing - это не типы а КОНСТРУТКОРЫ!!!! Тип здесь Maybe a. [...и далее по тексту...]

просто у вашего оппонента видимо нет понимания того, за что он борется :)

а так... да, вам +1 :)

Rastafarra ★★★★
()
Ответ на: комментарий от imp

>> Ну почему, я могу определить префиксный, инфиксный и постфиксный оператор. А еще есть (.) и flip чтобы эффективно писать.

Определитьоператор, а не изменить его синтаксис. Разницу чувствуешь? У тебя есть три синтаксические конструкции: infix, prefix, postfix... Доходит?

Про (.) и flip не понял? Это к чему?

>> А другие извращения с синтаксисом которые вы у себя в Лиспе вытворяете - суть есть изврат и есть более прямые способы добиваться того же...

И эти способы.... ????

cathode
()
Ответ на: комментарий от cathode

>И эти способы.... ????

Приведи осмысленный пример задачи и как она упрощается введением своего синтаксиса в Лиспе...

imp ★★
()
Ответ на: комментарий от Rastafarra

>> просто у вашего оппонента видимо нет понимания того, за что он борется :)

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

cathode
()
Ответ на: комментарий от imp

>> Приведи осмысленный пример задачи и как она упрощается введением своего синтаксиса в Лиспе...

Ну например каррированные функции :))

cathode
()
Ответ на: комментарий от cathode

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

+1

Потроллить все равно весело, и всегда найдется новый язык, который в чем то круче... :)

imp ★★
()
Ответ на: комментарий от cathode

>Ну например каррированные функции :))

зачем тут макросы?

-- | 'curry' converts an uncurried function to a curried function.
curry :: ((a, b) -> c) -> a -> b -> c
curry f x y = f (x, y)

-- | 'uncurry' converts a curried function to a function on pairs.
uncurry :: (a -> b -> c) -> ((a, b) -> c)
uncurry f p = f (fst p) (snd p)

imp ★★
()
Ответ на: комментарий от imp

> Приведи осмысленный пример задачи и как она упрощается введением своего синтаксиса в Лиспе...

Специальные языки для format и loop. Ладно с format'ом, но loop - это добавленный синтаксис. Заметь, у loop синтаксис не-lispish, и это как нельзя лучше доказывает, что в Лисп можно встроить практически любой язык.

mv ★★★★★
()
Ответ на: комментарий от mv

>Специальные языки для format и loop. Ладно с format'ом, но loop - это добавленный синтаксис. Заметь, у loop синтаксис не-lispish, и это как нельзя лучше доказывает, что в Лисп можно встроить практически любой язык.

Да можно такое через Template Haskell замутить, но смысла особого нет... Хаскелл не Лисп и смысля его в Лисп превращать нет никакого...

imp ★★
()
Ответ на: комментарий от imp

>> curry :: ((a, b) -> c) -> a -> b -> c
>> curry f x y = f (x, y)

А если параметров, скажем 5 или 7 штук? Или вообще неизвестно сколько их будет, как тогда? :))

cathode
()
Ответ на: комментарий от imp

> Да можно такое через Template Haskell замутить, но смысла особого нет... Хаскелл не Лисп и смысля его в Лисп превращать нет никакого...

Смысл: иметь синтаксис с человеческим языком.

mv ★★★★★
()
Ответ на: комментарий от imp

>> Да можно такое через Template Haskell замутить, но смысла особого нет... Хаскелл не Лисп и смысля его в Лисп превращать нет никакого...

В хаскеле нет call/cc поэтому он не Ъ ;)

cathode
()
Ответ на: комментарий от cathode

В хаскеле нет call/cc поэтому он не Ъ ;)

Есть http://en.wikibooks.org/wiki/Haskell/CPS Значит Ъ :)

Про curry с разными параметрами - по аналогии. А количество параметров всегда известно в Хаскелле. Для произвольного числа параметров искаропки нельзя, потому как нельзя в таком случае типы проверить...

imp ★★
()
Ответ на: комментарий от imp

>> Есть http://en.wikibooks.org/wiki/Haskell/CPS Значит Ъ :)

Всеравно Scheme более Ъ чем хаскель, потому что SICP написан с использованием схемы, а SICP это мега Ъ :))

>> Для произвольного числа параметров искаропки нельзя, потому как нельзя в таком случае типы проверить...

Вот поэтому в лиспе можно сделать макрос, чтобы было так (по аналогии со схемовским define):

(defcurr (func a b c d e f g) (...))

А в хаскеле нельзя сделать какой-нибудь новый = (например ==), чтобы получить некарированную ф-цию вот так:

func a b c == ...

cathode
()
Ответ на: комментарий от cathode

> А в хаскеле нельзя сделать какой-нибудь новый = (например ==), чтобы получить некарированную ф-цию вот так:

В хаскеле все функции каррированные, там такое вообще не надо.

Burbaka ★★
()
Ответ на: комментарий от Burbaka

>> В хаскеле все функции каррированные, там такое вообще не надо.

Ну если в хаскеле не нужны некаррированные функции, зачем тогда там есть uncurry ?

cathode
()
Ответ на: комментарий от imp

Насколько понимаю сontinuation в lisp и CPS в чисто функциональном языке несколько разные по возможностям конструкции. Или ошибаюсь ?

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

>Ну если в хаскеле не нужны некаррированные функции, зачем тогда там есть uncurry ?

Иногда проще применить uncurry и curry чем case и lambda, например:

let f a b c = a+b+c

(uncurry $ uncurry f) ((2,3),5)

let ((a,b),c) = ((2,3),5) in f a b c

imp ★★
()
Ответ на: комментарий от cathode

> Ну если в хаскеле не нужны некаррированные функции, зачем тогда там есть uncurry ?

Сам не знаю :) Оно "преобразует" каррированную функцию в функцию из двух аргументов в функцию получающую на вход один агругмент - тьюпл. Все равно что в Си

int foo(int a, int b) => int foo (struct { int a; int b; } c)

Я лично таким почти ни разу не пользовался

Burbaka ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.