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

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

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

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

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

8 ответов

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

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

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

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

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

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

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

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

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

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

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

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

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

И вуаля

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

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

Причины:

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

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

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

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

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

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