Haskell, Lisp и многословие

Для тех из вас, кто имел опыт работы как с Haskell, так и с некоторыми разновидностями Lisp, мне любопытно, насколько «приятно» (если использовать ужасный термин) писать код на Haskell и Lisp.

Немного предыстории: сейчас я изучаю Haskell, раньше работал со Scheme и CL (и немного углубился в Clojure). По традиции вы можете считать меня поклонником динамических языков за лаконичность и скорость, которые они обеспечивают. Я быстро влюбился в макросы Lisp, поскольку они дали мне еще один способ избежать многословия и шаблонности.

Я нахожу Haskell невероятно интересным, поскольку он знакомит меня со способами программирования, о существовании которых я не подозревал. В нем определенно есть некоторые аспекты, которые, как кажется, могут помочь в достижении гибкости, например, простота написания частичных функций. Однако меня немного беспокоит потеря макросов Lisp (я предполагаю, что теряю их; правда, я, возможно, просто еще не узнал о них?) И систему статической типизации.

Может ли кто-нибудь, кто сделал приличное количество кода в обоих мирах, прокомментировать, чем отличается опыт, что вы предпочитаете, и если это предпочтение является ситуативным?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
104
0
28 863
8

Ответы 8

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

В этом отношении Haskell сияет так же ярко, как и Common Lisp. Сочетание его функций дает вам способ программирования, делающий код чрезвычайно коротким и элегантным. Отсутствие макросов несколько смягчается более сложными (но также сложными для понимания и использования) концепциями, такими как монады и стрелки. Система статических типов увеличивает ваши возможности, а не мешает вам, как в большинстве объектно-ориентированных языков.

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

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

Не могли бы вы подробнее рассказать о «программировании на Haskell гораздо менее интерактивно». Разве GHCi не предоставляет все, что вам нужно?

Johannes Gerer 21.04.2013 13:11

@JohannesGerer: Я не пробовал, но, насколько я прочитал, GHCi не является оболочкой в ​​работающем образе, где вы можете переопределить и расширить произвольные части всей программы во время ее работы. Кроме того, синтаксис Haskell значительно усложняет программное копирование фрагментов программы между repl и редактором.

Svante 04.08.2013 14:55

Короткий ответ:

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

[Примечание: существует «Шаблон Haskell», который позволяет вам писать макросы так же, как в Lisp, но, строго говоря, вы никогда не должны нужно его.]

От Конора Макбрайда, цитируемого Доном Стюартом: «Мне нравится думать, что типы искажают нашу гравитацию, так что направление, в котором мы должны двигаться [для написания правильных программ], становится« под гору ». Система типов позволяет на удивление легко писать правильные программы… см. эта почта и его повторные публикации.

ShreevatsaR 19.11.2011 21:01

Функции высокого порядка не могут заменить макросы, и, фактически, в CL почему-то есть и то, и другое. Настоящая сила макросов в CL заключается в том, что они позволяют разработчику вводить новые языковые функции, которые помогают лучше выразить решение проблемы, не дожидаясь выхода новой версии языка, как в Haskell или Java. Например, если бы у Haskell была такая возможность, авторам Haskell не нужно было бы писать расширения GHC, если бы они могли быть реализованы самими разработчиками в виде макросов в любое время.

mljrg 14.09.2015 12:59

@mljrg У вас есть конкретный пример? См. Комментарии к ответу Hibou57 ниже, где предполагаемый пример оказался сомнительным. Мне было бы интересно узнать, что вы имеете в виду (например, код Haskell с макросами и без них).

ShreevatsaR 14.09.2015 19:46

Уберите каррирование из Haskell. Не могли бы вы реализовать это с тем, что осталось бы в Haskell? Другой пример: предположим, что Haskell не поддерживает сопоставление с образцом, не могли бы вы добавить его самостоятельно, чтобы разработчики GHC не поддерживали его? В CL вы можете использовать макросы для расширения языка по желанию. Я предполагаю, что именно поэтому CL язык не изменился со времени своего стандарта еще в 90-х, тогда как Haskell, похоже, имеет нескончаемый поток расширений в GHC.

mljrg 14.09.2015 19:57

По мере того как я продолжаю свое путешествие по изучению Haskell, мне кажется, что одна вещь, которая помогает «заменить» макросы, - это способность определять свои собственные инфиксные операторы и настраивать их приоритет и ассоциативность. Довольно сложная, но интересная система!

В Haskell меньше необходимости в метапрограммировании, чем в Common Lisp, потому что многое можно структурировать вокруг монад, а добавленный синтаксис делает встроенные DSL менее древовидными, но всегда есть Template Haskell, как упоминалось в ShreevatsaR, и даже Лискелл (семантика Haskell + Lisp синтаксис), если вам нравятся круглые скобки.

Liskell ссылка на сайт мертв, но в наши дни есть Hackett.

Will Ness 14.06.2018 13:38

В Haskell вы можете определить функцию if, что невозможно в LISP. Это возможно из-за лени, которая делает программы более модульными. В этой классической статье: Почему важна FP Джона Хьюза объясняется, как лень улучшает возможность компоновки.

Схема (один из двух основных диалектов LISP) действительно имеет ленивое вычисление, хотя это не по умолчанию, как в Haskell.

Randy Voet 09.09.2009 18:47

(defmacro doif (x y) `(если, x, y))

Joshua Cheek 20.11.2010 14:52

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

Tikhon Jelvis 24.05.2013 11:01

Я программист на Common Lisp.

Некоторое время назад я попробовал Haskell, и в итоге я решил придерживаться CL.

Причины:

У Haskell, конечно, есть свои достоинства, и некоторые вещи он делает принципиально по-другому, но в долгосрочной перспективе он меня не решает.

Эй, у вас случайно есть название той статьи Костанцы, на которую вы ссылались? Похоже, этот файл был перемещен.

michiakig 27.08.2010 19:27

Возможно, это был такой: p-cos.net/documents/dynatype.pdf

Leslie P. Polzer 01.09.2010 12:09

Обратите внимание, что haskell также поддерживает синтаксис префикса, но я бы сказал, что использование monad >> = было бы очень некрасивым. Также я не согласен с тем, что нечистота является благословением: P

alternative 08.04.2011 05:06

Мне нравится это примечание: Мы еще не собрали эмпирических данных, вызывает ли эта проблема серьезные проблемы в реальных программах.

Jerome Baum 17.10.2011 22:31

Ни один из примеров в этой статье (Pascal Costanza, Динамический и статический набор текста - анализ на основе шаблонов) не применим к Haskell. Все они специфичны для Java (или, точнее, специфичны для "объектно-ориентированное программирование"), и я не вижу ни одной из этих проблем, возникающих в Haskell. Точно так же все ваши другие аргументы спорны: можно также сказать, что Haskell «чистый и, следовательно, больше подходит для быстрого прототипирования», что синтаксис префикса не является обязательным, что у него нет большого количества компиляторов, которые делают разные вещи , так далее.

ShreevatsaR 12.12.2011 21:16

Эта статья действительно почти не имеет отношения к Haskell. "dilbert = dogbert.hire(dilbert);" ?? Я сомневаюсь, что многие программисты на Haskell могут даже прочитать это, не вздрогнув.

leftaroundabout 12.01.2012 19:42

Есть действительно интересные вещи, которых вы можете достичь в Лиспе с помощью громоздких (если возможно) макросов в Haskell. Возьмем, к примеру, макрос «memoize» (см. Главу 9 PAIP Питера Норвига). С его помощью вы можете определить функцию, скажем foo, а затем просто оценить (memoize 'foo), которая заменяет глобальное определение foo мемоизированной версией. Можете ли вы добиться того же эффекта в Haskell с помощью функций высшего порядка?

Не совсем (AFAIK), но вы можете сделать что-то подобное, изменив функцию (при условии, что она рекурсивна), чтобы функция рекурсивно вызывалась в качестве параметра (!), А не просто вызывала себя по имени: haskell.org/haskellwiki/Memoization

j_random_hacker 29.03.2010 06:05

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

Theo Belaire 27.04.2011 03:29

Все в Haskell запомнено и, вероятно, встроено, когда это необходимо по умолчанию компилятором Haskell.

aoeu256 01.09.2019 16:59

Что касается макросов, вот страница, на которой об этом говорится: Привет, Haskell, прощай, Лисп. Это объясняет точку зрения, согласно которой макросы в Haskell просто не нужны. Для сравнения прилагается небольшой пример.

Пример случая, когда требуется макрос LISP, чтобы избежать оценки обоих аргументов:

(defmacro doif (x y) `(if ,x ,y))

Пример случая, когда Haskell не оценивает систематически оба аргумента без необходимости в каком-либо макроопределении:

doif x y = if x then (Just y) else Nothing

И вуаля

Это распространенное заблуждение. Да, в Haskell лень означает, что вам не нужны макросы, когда вы не хотите оценивать некоторые части выражения, но это только самое тривиальное подмножество всех применений макросов. Google для "Свинья до Perl" за доклад, демонстрирующий макрос, который нельзя сделать ленивым. Кроме того, если вы делать хотите, чтобы какой-то бит был строгим, вы не можете сделать это как функцию - отражая тот факт, что delay Scheme не может быть функцией.

Eli Barzilay 24.02.2010 03:22

@ Эли Барзилай: Я не считаю этот пример очень убедительным. Вот полный, простой перевод слайда 40 на Haskell: pastebin.com/8rFYwTrE

Reid Barton 23.09.2010 16:42

@ Рид Бартон: А? Основная идея этого документа - создание макрос, который на самом деле является небольшим DSL для определения автоматов, которые "компилируются" в код схемы. Ваш код, OTOH, является своего рода простым переводом кода, но (а) он использует поиск по таблице, о котором Шрирам говорит в начале, и, что гораздо важнее, (б) вы используете простой Haskell, и результат все еще далек от определения такого DSL. AFAICT, единственное, что это демонстрирует, это «легко написать такой код, проще, когда вы можете использовать значения функций в таблице». То есть, к макросам мало что относится.

Eli Barzilay 24.09.2010 07:00

@ Эли Барзилай: Я вообще не понимаю вашего ответа. acceptявляется (E) DSL. Функция accept является аналогом макроса, описанного на предыдущих страницах, а определение v точно аналогично определению v на схеме на слайде 40. Функции Haskell и Scheme вычисляют то же самое с той же стратегией оценки. В лучшем случае макрос позволяет вам раскрыть оптимизатору большую часть структуры вашей программы. Вряд ли вы можете назвать это примером, когда макросы увеличивают выразительную силу языка так, как это не воспроизводится ленивым вычислением.

Reid Barton 24.09.2010 08:59

Я не слежу ни за чем из этого. Прежде всего, да - accept - это функция, которая выполняет работу, но это не DSL, это функция, как и все другие функции, и такие вещи, как использование ее во всех подсписках или необходимое использование where с его собственная область видимости - это именно то, что делает макрос ненужным. Что касается ленивой оценки - вы не используете ее каким-либо существенным образом, поэтому я не понимаю, насколько уместен весь этот аргумент.

Eli Barzilay 24.09.2010 18:47

@Eli Barzilay: В гипотетической ленивой схеме вы могли бы написать это: pastebin.com/TN3F8VVE Мое общее утверждение состоит в том, что этот макрос мало что вам дает: немного другой синтаксис и более простое время для оптимизатора (но это не имеет значения для «достаточно умного» компилятор "). Взамен вы загнали себя в ловушку невыразительного языка; как определить автомат, который соответствует любой букве, не перечисляя их все? Кроме того, я не знаю, что вы имеете в виду, говоря «использовать его во всех подсписках» или «обязательное использование where с его собственной областью действия».

Reid Barton 04.10.2010 00:17

Рид: (а) ленивый план не является гипотетическим - один из них был частью Racket в течение нескольких лет; (б) факт, что макросы все еще полезны, есть хорошая подсказка; (c) то, что вы написали, также показывает, почему макрос полезен - он не использует его и, следовательно, не является тем DSL, о котором говорит Шрирам; (г) под «использованием его в подсписках» и т. д. я имел в виду, что у вас есть определенные требования к вашему «DSL», которые исходят от реализации (например, использование accept) - это одна из причин, почему это нет как DSL;

Eli Barzilay 04.10.2010 03:32

(e) Иллюзия того, что лень делает макросы управления потоком (те, которые не имеют новых привязок) избыточными, может рассматриваться как фикция, если вы думаете о добавлении строгого оператора к ленивому языку - для использования такого оператора требуются специальные формы (и макросы ) тоже; (е) еще один момент: если в Haskell макросы не нужны, почему они у него есть? (И даже до TH использовался CPP.)

Eli Barzilay 04.10.2010 03:35

Наконец, (ж) убедитесь, что вы ловите себя на «невыразительном языке» - все дело в DSL, а не в GPL. Очевидно, что можно написать более сложный макрос, который будет иметь выражения Scheme (например, предикат для символа, вместо того, чтобы перечислять их все), но в этом примере это выходит за рамки DSL.

Eli Barzilay 04.10.2010 03:37

Хорошо, я сдаюсь. По-видимому, ваше определение DSL - это «аргументы макроса», и поэтому мой пример с ленивой схемой не является DSL, несмотря на то, что он синтаксически изоморфен оригиналу (automaton становится letrec, : становится accept, -> становится ничем в этой версии). Что бы ни.

Reid Barton 05.10.2010 06:37

Ссылка в этом посте кажется неработающей @ Hibou57, не могли бы вы проверить и при необходимости исправить свое сообщение?

batbrat 26.02.2014 22:03

@batbrat, исправлено, и спасибо, что уведомили меня о проблеме (они изменили расположение своих URL-адресов на этом сайте).

Hibou57 27.02.2014 21:01

Другие вопросы по теме