Haskell, Lisp та багатослівність [закрито]


104

Для тих, хто з вас відчував і Haskell, і якийсь аромат Ліспа, мені цікаво, наскільки "приємно" (вживати жахливий термін) - написати код у Haskell vs. Lisp.

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

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

Хто-небудь, хто зробив пристойну кількість кодування в обох світах, коментуючи те, як відрізняються переживання, які ви віддаєте перевагу, і якщо ці переваги є ситуаційними?

Відповіді:


69

Коротка відповідь:

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

[Примітка: Існує " Шаблон Haskell ", який дозволяє писати макроси так само, як у Lisp, але строго кажучи, вам це ніколи не потрібно .]


15
Від Конора Макбріда, якого цитує Дон Стюарт: "Мені подобається думати про типи, як про викривлення нашої сили тяжіння, так що напрямок, який нам потрібно подорожувати [для написання правильних програм], стає" вниз ". Система типу дозволяє напрочуд легко писати правильні програми ... дивіться цю публікацію та її повторну подію.
ShreevatsaR

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

@mljrg У вас є конкретний приклад? Дивіться коментарі до відповіді Hibou57 нижче, де нібито приклад виявився сумнівним. Мені було б цікаво дізнатися про тип речі, який ви маєте на увазі (наприклад, код Haskell з макросами та без них).
ShreevatsaR

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

64

Перш за все, не турбуйтеся про втрату конкретних функцій, таких як динамічне введення тексту. Як ви знайомі з Common Lisp, надзвичайно добре розробленою мовою, я припускаю, що ви знаєте, що мова не може бути зведена до її набору функцій. Це все про цілісне ціле, чи не так?

У зв'язку з цим Хаскелл світить так само яскраво, як і звичайний Лісп. Його функції поєднуються, щоб забезпечити вам спосіб програмування, який робить код надзвичайно коротким та елегантним. Відсутність макросів дещо пом'якшується більш детальними (але, тим самим, важче зрозуміти та використовувати) такі поняття, як монади та стріли. Система статичного типу додає ваші сили, а не заважає, як це робиться в більшості об'єктно-орієнтованих мов.

З іншого боку, програмування в Haskell набагато менш інтерактивне, ніж Lisp, і величезна кількість роздумів, присутніх на таких мовах, як Lisp, просто не відповідає статичному погляду на світ, який передбачає Haskell. Отже, доступні набори інструментів сильно відрізняються між двома мовами, але їх важко порівняти.

Я особисто віддаю перевагу способу програмування Lisp в цілому, оскільки вважаю, що він підходить тому, як я краще працюю. Однак це не означає, що ви також зобов'язані це робити.


4
Не могли б ви детальніше зупинитися на тому, що "програмування в Haskell набагато менш інтерактивне". Чи справді GHCi не забезпечує все необхідне?
Йоханнес Герер

3
@JohannesGerer: Я не пробував цього, але, наскільки я прочитав, GHCi - це не оболонка в запущеному зображенні, де ви можете переосмислити і розширити довільні частини всієї програми, поки вона працює. Крім того, синтаксис Haskell значно ускладнює програмне копіювання фрагментів програми між repl та редактором.
Svante

13

У Haskell метапрограмування потрібно менше, ніж у Common Lisp, тому що багато чого можна структурувати навколо монад, а доданий синтаксис робить вбудовані DSL менш схожими на дерева, але завжди існує шаблон Haskell, як згадує ShreevatsaR , і навіть Liskell (Haskell семантика + Lisp синтаксис), якщо вам подобаються дужки.


1
посилання Ліскелл мертва, але в наші дні є Хакетт .
Буде Несс

10

Щодо макросів, ось сторінка, на якій розповідають про це: Hello Haskell, Goodbye Lisp . Це пояснює точку зору, де макроси просто не потрібні в Haskell. Він подається з коротким прикладом для порівняння.

Приклад випадку, коли потрібен макрос LISP, щоб уникнути оцінки обох аргументів:

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

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

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

І вуаля


17
Це поширене оману. Так, в Haskell лінь означає, що вам не потрібні макроси, коли ви хочете уникати оцінки деяких частин виразу, але це лише найтривіальніший підмножина з усіх макрокористувань. Google для "Свині перед Перлом" - для бесіди, що демонструє макрос, який неможливо зробити з лінню. Крім того , якщо ви дійсно хочете , щоб деякі трохи бути строгим, то ви не можете зробити це як функція - дзеркальне відображення того , що схема - х delayне може бути функцією.
Елі Барзілай

8
@Eli Barzilay: Я не вважаю цей приклад дуже переконливим. Ось повний простий Haskell переклад слайда 40: pastebin.com/8rFYwTrE
Reid Barton

5
@Eli Barzilay: Я взагалі не розумію вашої відповіді. accept є (E) DSL. acceptФункція є аналогом макросу , викладеним на попередніх сторінках, а також визначення vв точності паралельно з визначенням vв схемі на слайді 40. Функція Haskell і Scheme обчислити те ж саме , з тією ж самою стратегією оцінки. У кращому випадку макрос дозволяє піддавати оптимізатору більше структури вашої програми. Навряд чи можна стверджувати це як приклад, коли макроси збільшують виразну силу мови таким чином, що не повторюється ледачим оцінкою.
Рейд Бартон,

5
@Eli Barzilay: У гіпотетичній ледачій схемі ви можете написати це: pastebin.com/TN3F8VVE Моє загальне твердження, що цей макрос купує вам дуже мало: трохи інший синтаксис і простіший час для оптимізатора (але це не має значення для "достатньо розумний компілятор"). В обмін ви захопили себе невиразною мовою; як ви визначаєте автомат, який відповідає будь-якій букві, не перераховуючи їх усіх? Крім того, я не знаю, що ви маєте на увазі, "використовуючи його у всіх під-списках" або "необхідне використання куди з власною сферою дії".
Рейд Бартон

15
Гаразд, я здаюсь. Мабуть, ваше визначення DSL - це "аргументи макросу", і тому мій лінивий приклад схеми - це не DSL, незважаючи на те, що синтаксично ізоморфний оригіналу ( automatonстає letrec, :стає accept, ->стає нічим у цій версії). Що б там не було.
Рейд Бартон

9

Я звичайний програміст Lisp.

Спробувавши Haskell деякий час тому, мій особистий підсумок полягав у дотриманні CL.

Причини:

  • динамічне введення тексту (перевірити динамічне проти статичного набору тексту - аналіз на основі шаблону Паскаля Костанца )
  • необов’язкові та ключові аргументи
  • рівномірний синтаксис гомоніконічного списку з макросами
  • синтаксис префікса (не потрібно пам'ятати правила пріоритету)
  • нечисті і, таким чином, більше підходять для швидкого прототипування
  • потужна об’єктна система з протоколом мета-об'єкта
  • зрілий стандарт
  • широкий спектр компіляторів

Звичайно, у Haskell є свої достоїнства, і деякі речі робить принципово по-іншому, але це просто не вирішує це в довгостроковій перспективі для мене.


Гей, чи трапляється у вас назва документа Костанца, з яким ви пов’язані? Схоже, цей файл переміщено.
michiakig

2
Зауважте, що haskell теж підтримує синтаксис префікса, але я б сказав, що monad >> = було б дуже некрасиво, використовуючи його. Також я не погоджуюся з тим, що нечистота є благословенням: P
альтернатива

2
Мені подобається ця сторона: ми ще не зібрали емпіричних даних, чи викликає це питання серйозні проблеми в реальних програмах.
Джером Баум

22
Жоден із прикладів у цій роботі (Паскаль Костанца, Динамічне проти Статичного Введення - Аналіз на основі шаблону ) не стосується Хаскелла. Всі вони є специфічними для Java (а точніше, специфічними для "об'єктно-орієнтованого програмування" ), і я не бачу жодної з цих проблем, що виникають у Haskell. Аналогічно, всі ваші інші аргументи є дискусійними: можна також сказати, що Haskell "чистий і, таким чином, більше підходить для швидкого прототипування", що синтаксис префікса не є обов'язковим, що він не має широкого кола компіляторів, які роблять різні речі і т. д.
ShreevatsaR

11
Цей документ справді майже абсолютно не має значення для Haskell. " dilbert = dogbert.hire(dilbert);" ?? Сумніваюсь, багато програмістів Haskell навіть можуть це прочитати, не посміхаючись.
близько

6

У Haskell можна визначити функцію if, що неможливо в LISP. Це можливо через лінь, що дозволяє отримати більше модульності в програмах. Цей класичний документ: Чому важливі FP від Джона Х'юза, пояснює, як лінь підвищує композиційність.


5
Схема (один з двох основних діалектів LISP) насправді має ледачу оцінку, хоча це не за замовчуванням, як у Haskell.
Ренді Воет

7
(defmacro doif (xy) `(якщо, x, y))
Джошуа Щока

4
Макрос не те ж саме , як функція - макроси не працюють добре з функціями вищого порядку , як fold, наприклад , в той час як несуворі функції роблять .
Тихон Єлвіс

5

Є справді прикольні речі, яких можна досягти в Ліспі за допомогою макросів, які є громіздкими (якщо можливо) в Haskell. Візьмемо для прикладу макрос `memoize '(див. Розділ 9 PAIP Пітера Норвіга). За допомогою нього можна визначити функцію, скажімо, foo, а потім просто оцінити (запам'ятати 'foo), яка замінює глобальне визначення foo запам'ятовуваною версією. Чи можете ви досягти такого ж ефекту в Haskell за допомогою функцій вищого порядку?


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

6
Ви можете додати foo до ледачої структури даних, де значення буде зберігатися після обчислення. Це буде ефективно те саме.
Тео Белер

Все в Haskell запам'ятовується і, ймовірно, накреслюється, коли це потрібно за замовчуванням компілятором Haskell.
aoeu256

4

Поки я продовжую свою подорож до навчання Haskell, здається, що одне, що допомагає "замінити" макроси, - це можливість визначати власні оператори інфіксації та налаштовувати їх перевагу та асоціативність. Ніби складна, але цікава система!

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.