Haskell або Standard ML для початківців? [зачинено]


78

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

Я хочу, щоб зрозуміла мова FP ілюструвала концепції DS та якими можуть користуватися студенти. Більшість студентів мали б у кращому випадку лише один-два семестри програмування на Java. Подивившись на Scheme, Erlang, Haskell, Ocaml та SML, я зупинився на Haskell або Standard ML. Я схиляюся до Haskell з причин, викладених нижче, але я хотів би думки тих, хто є активним програмістом в тому чи іншому.

  • І Haskell, і SML мають узгодження шаблонів, що робить опис рекурсивного алгоритму надзвичайним.
  • Haskell має чудові розуміння списків, які добре поєднуються з способом математичного вираження таких списків.
  • Хаскелл має ліниву оцінку. Чудово підходить для побудови нескінченних списків за допомогою техніки розуміння списків.
  • SML має справді інтерактивний інтерпретатор, в якому функції можна як визначати, так і використовувати. У Haskell функції повинні бути визначені в окремому файлі та скомпільовані перед використанням в інтерактивній оболонці.
  • SML дає явне підтвердження аргументу функції та типів повернення в синтаксисі, який легко зрозуміти. Наприклад: val foo = fn: int * int -> int. Явний синтаксис каррі Хаскелла трохи більш тупий, але не зовсім чужий. Наприклад: foo :: Int -> Int -> Int.
  • Haskell використовує цілі числа довільної точності за замовчуванням. Це зовнішня бібліотека в SML / NJ. А за замовчуванням SML / NJ скорочує вивід до 70 символів.
  • Лямбда-синтаксис Хаскелла тонкий - він використовує одну зворотну косу риску. SML є більш явним. Не впевнений, що нам коли-небудь знадобиться лямбда в цьому класі.

По суті, SML і Haskell приблизно еквівалентні. Я схиляюся до Хаскелла, тому що люблю розуміння списків і нескінченні списки в Хаскелі. Але я переживаю, що велика кількість символів у компактному синтаксисі Хаскелла може викликати проблеми у студентів. З того, що я зібрав, читаючи інші дописи про SO, Haskell не рекомендується для початківців, починаючи з FP. Але ми не збираємося створювати повноцінні додатки, просто випробувавши прості алгоритми.

Як ти гадаєш?


Редагувати: Прочитавши деякі ваші чудові відгуки, я мав би пояснити деякі мої моменти.

У SML немає синтаксичної різниці між визначенням функції в інтерпретаторі та визначенням її у зовнішньому файлі. Скажімо, ви хочете написати факторіальну функцію. У Haskell ви можете помістити це визначення у файл і завантажити в GHCi:

fac 0 = 1
fac n = n * fac (n-1)

Для мене це зрозуміло, стисло і відповідає математичному визначенню в книзі. Але якщо ви хочете написати функцію безпосередньо в GHCi, вам доведеться використовувати інший синтаксис:

let fac 0 = 1; fac n = n * fac (n-1)

Працюючи з інтерактивними перекладачами, з точки зору викладання дуже, дуже зручно, коли студент може використовувати один і той же код як у файлі, так і в командному рядку.

Під "явним підтвердженням функції" я мав на увазі, що після визначення функції SML відразу повідомляє вам назву функції, типи аргументів і тип повернення. У Haskell вам потрібно скористатися :typeкомандою, і тоді ви отримаєте дещо заплутане позначення каррі.

Ще одна крута річ про Haskell - це дійсне визначення функції:

fac 0 = 1
fac (n+1) = (n+1) * fac n

Знову ж таки, це відповідає визначенню, яке вони можуть знайти в підручнику. Не можу цього зробити в SML!


3
Щодо перекладача Хаскелла, це лише деякі конкретні обмеження GHCi. Можливо, деякі інші перекладачі Haskell можуть мати кращу поведінку. Ви можете визначати значення та функції у ghci, лише не типи даних. Ви повинні почати з того, що говорите "нехай". Крім того, кожен вхід повинен бути в одному рядку, тому замість багаторядкового синтаксису, вирівняного за відступами для кількох визначень у "let" або для операторів у "do" або "case", вам доведеться розділяти їх крапками з комою , і оточіть його дужками. наприклад "нехай {факт 0 = 1; факт n = n * факт (n-1)}". Крім того, речення "де" не працюють. Це стає трохи втомливим
newacct

Щодо каррингу, SML має таку ж підтримку карріювання та синтаксис, як у Haskell. Наприклад, у SML "fun foo xy = x * y" - це помножене на каре. Просто з якихось причин домовленість у SML полягає в тому, що множинні аргументи повинні наводитися як один аргумент кортежу, а не як аргументи, що піддаються карі. (Зауважте, що OCaml, однак, дотримується звичаїв, на відміну від SML.) Однак це не є абсолютним правилом; функції, які часто застосовуються частково, виконуються в SML. Наприклад, функція "map" у SML викривляється, маючи тип "('a ->' b) -> 'a list ->' b list".
newacct

Haskell за замовчуванням має як цілі числа із фіксованою точністю (Int), так і цілі числа з довільною точністю (Integers). Просто, коли він не обмежений, перекладач просто вибирає найширший з них - це Integer. Однак деякі функції приймають лише Int, наприклад, оператор індексації списку (!!).
newacct

11
На жаль для вас, синтаксис fac (n + 1) вилучається із наступного стандарту Haskell, тому не надто звикайте
GS - Вибачте перед Моніка

1
Ей, Баррі, цікаво, що ти думаєш з цього приводу? tryhaskell.org Мені було б цікаво дізнатись, чи можете ви розглянути можливість використання цього онлайн-механізму навчання Haskell для навчання студентів. Я б допоміг, якщо ви хочете це змінити. Приклад можливого: tryhaskell.org/… Детальніше про реалізацію тут: chrisdone.com/posts/… Я спочатку писав це з надією, що хтось використає його для навчання. Ми могли б розширити його таким чином, що натискання return означає ";".
ChristopherЗакінчено

Відповіді:


90

Оскільки я люблю Haskell, ось причини, я би віддав перевагу SML для класу з дискретною математикою та структурами даних (та більшості інших класів для початківців):

  • Часові та космічні витрати програм Haskell може бути дуже важко передбачити навіть для експертів. SML пропонує набагато обмеженіші способи продувки машини.

  • Синтаксис визначення функції в інтерактивному інтерпретаторі ідентичний синтаксису, який використовується у файлі, тому ви можете вирізати та вставити.

  • Хоча перевантаження оператора в SML є абсолютно фіктивним, воно також є простим. Буде важко викладати цілий клас у Хаскеллі, не маючи необхідності потрапляти на курси типу.

  • Студент може налагоджувати за допомогою print. (Хоча, як зазначає коментатор, можна отримати майже такий же ефект у Haskell, використовуючи Debug.Trace.trace.)

  • Нескінченні структури даних вражають розум людей. Для початківців вам краще дозволити їм визначити тип потоку в комплекті з клітинками ref і thunks, щоб вони знали, як це працює:

    datatype 'a thunk_contents = UNEVALUATED of unit -> 'a
                               | VALUE of 'a
    type 'a thunk = 'a thunk_contents ref
    val delay : (unit -> 'a) -> 'a thunk
    val force : 'a thunk -> 'a
    

    Тепер це вже не магія, і ви можете переходити звідси до потоків (нескінченні списки).

  • Макет не такий простий, як у Python, і може заплутати.

Є два місця, де Haskell має перевагу:

  • У основному Haskell ви можете написати підпис типу функції безпосередньо перед її визначенням. Це надзвичайно корисно для студентів та інших початківців. Просто не є приємним способом мати справу з підписами типів у SML.

  • Haskell має кращий конкретний синтаксис. Синтаксис Haskell є значним покращенням порівняно з синтаксисом ML. Я написав коротку нотатку про те, коли використовувати дужки в програмі ML ; це трохи допомагає.

Нарешті, є меч, який вирізає обидва шляхи:

  • За замовчуванням код Haskell є чистим, тому ваші студенти навряд чи випадково натраплять на нечисті конструкції (монада IO, монада штату). Але, тим самим чином, вони не можуть друкувати, і якщо ви хочете зробити введення-виведення, тоді як мінімум ви повинні пояснити doпозначення, і returnце бентежить.

Щодо суміжної теми, ось кілька порад щодо підготовки курсу: не нехтуйте чисто функціональними структурами даних Кріса Окасакі. Навіть якщо у вас немає студентів, якими ви хочете користуватися, ви точно захочете мати копію.


Приємна відповідь! Я ще раз подивлюся на SML. Майте на увазі, мої знання як про Haskell, так і про SML обмежуються кількома годинами, що працюють в Інтернеті та читанні книг. Я ще не копався в тонших деталях. Чи можете ви допомогти з цим питанням? stackoverflow.com/questions/740896
Баррі Браун, 02

13
Домовились про все, крім налагодження "друку". Ви можете використовувати його в Haskell. Є обидва Debug.Trace.trace :: String -> a -> aі Debug.Trace.traceShow :: (Show a) => a -> b -> bдоступні, які обходять обмеження IO () і охоче виводять трасування.
віраптор

1
<«Синтаксис Haskell є значним покращенням порівняно з синтаксисом ML. Я написав коротку нотатку про те, коли використовувати дужки в програмі ML; це трохи допомагає »>: справді ... одна з речей, яка мені не подобається в SML, - це неоднозначність, яка може з’явитися із заявами Case. Я вважаю, що SML повинен вимагати дужок навколо нього, щоб уникнути двозначності, коли вони вкладені. Загалом, не так вже й велика кількість прикрощів, які я відчуваю щодо SML, є синтаксичними.
Hibou57,

3
можливо, ви захочете ознайомитися з курсом NICTA Haskell для початківців: github.com/NICTA/course
Ерік Каплун

3
В останніх версіях GHC синтаксис визначення функцій ідентичний (більше не потрібно let).
ThreeFx

29

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

Деякі проблеми, які я помічав у студентів, часто мають:

  • Спочатку узгодження зразків може бути дещо складним. Спочатку студенти мали проблеми з тим, як пов’язані побудова значень та узгодження зразків. Вони також мали деякі проблеми з розмежуванням абстракцій. Наші вправи включали функції письма, які спрощують арифметичне вираження, і деяким студентам було важко побачити різницю між абстрактним поданням (наприклад, Const 1) та метамовним поданням ( 1).

    Крім того, якщо ваші студенти повинні самі писати функції обробки списків, будьте обережні, вказуючи на різницю між шаблонами

    []
    [x]
    (x:xs)
    [x:xs]
    

    Залежно від того, наскільки функціональному програмуванню ви хочете навчити їх у дорозі, ви можете просто надати їм кілька бібліотечних функцій і дозволити їм пограти з цим.

  • Ми не вчили наших студентів про анонімні функції, ми просто розповідали їм про whereпункти. Для деяких завдань це було трохи багатослівно, але в іншому випадку це працювало добре. Ми також не розповідали їм про часткові заявки; це, мабуть, досить легко пояснити в Haskell (завдяки формі письма), тому, можливо, варто їм показати.

  • Вони швидко виявили спискові і вважали за краще їх більш високий порядку функції , такі як filter, map, zipWith.

  • Я думаю, ми трохи пропустили, навчивши їх, як дозволити їм направляти свої думки за типами. Однак я не зовсім впевнений, корисно це для початківців чи ні.

  • Повідомлення про помилки зазвичай не дуже корисні для початківців, їм іноді може знадобитися допомога з ними. Я не пробував сам, але є компілятор Haskell, спеціально орієнтований на новачків, головним чином за допомогою кращих повідомлень про помилки: Гелій

  • Для невеликих програм такі речі, як можливі витоки простору, не були проблемою.

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


3
Яка різниця між шаблонами (x: xs) та [x: xs]?
Ківі

15
(x:xs)відповідає непустому списку, тобто аргумент повинен мати тип [a]. [x:xs]відповідає списку singleton, який містить непустий список, тобто аргумент повинен мати тип [[a]]. [x:xs]те саме, [(x:xs)]що те саме, що ((x:xs):[]).
nominolo

Щодо: "З одного боку, викладання Хаскелла на перших курсах означає, що їм не потрібно вивчати імперативний стиль": Я б не сприймав це як належне. Багато студентів вже матимуть деякі знання програмування з класів середньої школи, графічних калькуляторів тощо
ruahh

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

@SimonShine Як лінивість може бути проблемою?
olyk

14

До речі,

# SML має справді інтерактивний інтерпретатор, в якому функції можна як визначати, так і використовувати. У Haskell функції повинні бути визначені в окремому файлі та скомпільовані перед використанням в інтерактивній оболонці.

Є неточним. Використовуйте GHCi:

Prelude> let f x = x ^ 2
Prelude> f 7
49
Prelude> f 2
4

Також є хороші ресурси для Haskell в освіті на haskell.org edu. сторінку, з досвідом від різних викладачів. http://haskell.org/haskellwiki/Haskell_in_education

Нарешті, ви зможете навчити їх багатоядерному паралелізму просто для розваги, якщо скористаєтесь Haskell :-)


6
Я пояснив свою заяву щодо перекладача SML проти Haskell. Норман Ремзі сказав це краще: скопіюйте та вставте з інтерпретатора у файл.
Barry Brown 02

4
Зверніть увагу, що SML - це не просто SML / NJ, який є одноядерним. Poly / ML підтримує власні потоки, а доповнення Isabelle / ML - зручні абстракції, такі як паралельні списки та ф'ючерси.
Makarius

12

Багато університетів викладають Haskell як першу функціональну мову або навіть як першу мову програмування, тому я не думаю, що це буде проблемою.

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

Я б також не погодився з будь-якою припущенням, що Haskell не рекомендується для початківців, які починають з FP. Це, звичайно, підхід "великого вибуху" таким чином, що суворі мови з мутацією не є, але я думаю, що це дуже вагомий підхід.


1
Я бачив, як деякі університети чергують Хаскелла та ML, залежно від того, хто викладав курс.
hbw

9
  • SML має справді інтерактивний інтерпретатор, в якому функції можна як визначати, так і використовувати. У Haskell функції повинні бути визначені в окремому файлі та скомпільовані перед використанням в інтерактивній оболонці.

Хоча обійми можуть мати таке обмеження, GHCi не:

$ ghci
GHCi, version 6.10.1: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer ... linking ... done.
Loading package base ... linking ... done.
Prelude> let hello name = "Hello, " ++ name
Prelude> hello "Barry"
"Hello, Barry"

Є багато причин, чому я віддаю перевагу GHC (i) перед Hugs, це лише одна з них.

  • SML дає явне підтвердження аргументу функції та типів повернення в синтаксисі, який легко зрозуміти. Наприклад: val foo = fn: int * int -> int. Явний синтаксис каррі Хаскелла трохи більш тупий, але не зовсім чужий. Наприклад: foo :: Int -> Int -> Int.

SML також має те, що ви називаєте синтаксисом "неявного каррі".

$ sml
Standard ML of New Jersey v110.69 [built: Fri Mar 13 16:02:47 2009]
- fun add x y = x + y;
val add = fn : int -> int -> int

По суті, SML і Haskell приблизно еквівалентні. Я схиляюся до Хаскелла, тому що люблю розуміння списків і нескінченні списки в Хаскелі. Але я переживаю, що велика кількість символів у компактному синтаксисі Хаскелла може викликати проблеми у студентів. З того, що я зібрав, читаючи інші дописи про SO, Haskell не рекомендується для початківців, починаючи з FP. Але ми не збираємося створювати повноцінні додатки, просто випробувавши прості алгоритми.

Мені подобається використовувати Haskell набагато більше, ніж SML, але я все одно вчив би спочатку SML.

  • Відправляючи думки номіноло, розуміння списку , здається, сповільнює студентів дістатися до деяких функцій вищого порядку.
  • Якщо вам потрібні лінощі та нескінченні списки, корисно реалізувати це явно.
  • Оскільки SML ретельно оцінюється, модель виконання набагато легша для сприйняття, і "налагодження через printf" працює набагато краще, ніж у Haskell.
  • Система типу SML також простіша. У той час як ваш клас , ймовірно , не використовуватиме їх в будь-якому випадку, класи типів Haskell є ще додатковий удар , щоб отримати більш - змусити їх зрозуміти в 'aпорівнянні з ''aрізницею в SML є досить жорстким.

7

Більшість відповідей були технічними, але я думаю, ви повинні розглянути хоча б одну, яка не є такою: Haskell (як OCaml), на даний момент, має більшу спільноту, яка використовує її в більш широкому контексті. Також існує велика база даних бібліотек та додатків, написаних для отримання прибутку та розваг у Hackage . Це може бути важливим фактором у тому, щоби деякі з ваших студентів користувалися мовою після закінчення курсу, а, можливо, і спробувати інші функціональні мови (наприклад, Standard ML) пізніше.


5

Я вражений, що ви не розглядаєте OCaml та F #, враховуючи те, що вони вирішують стільки ваших проблем. Напевно, гідне та корисне середовище для розробки є пріоритетом для учнів? SML на цьому відстає, а F # - набагато попереду всіх інших FPL.

Крім того, як OCaml, так і F # мають розуміння списків.


1
Я розглянув обидва. Одне, зокрема, мене турбує щодо OCaml: синтаксис визначення рекурсивної та нерекурсивної функції дещо відрізняється. Нам це здається дрібницею, але для новачка, який має достатньо проблем із синтаксисом, це може бути великою справою. Я шукаю інструменти, які дозволять мені якнайшвидше дійти до суті справи. Я серйозно не замислювався над F #, оскільки це мова лише для Microsoft.
Barry Brown

1
В OCaml ви використовуєте "let" для нерекурсивних визначень значень або функцій і "let rec" для рекурсивних визначень. У SML ви зазвичай використовуєте "val" для нефункціональних значень і "fun" для функцій, за винятком випадків, коли вони є нерекурсивною заміною попередніх функцій, і в цьому випадку ви повинні використовувати "val" та лямбда-функцію на верхньому рівні або "let val" і лямбда-функція, якщо вона вкладена. Досить сказати, шлях OCaml мені здається набагато зрозумілішим. Крім того, у вас немає таких речей, як типи рівності, для пояснення.
JD

Незважаючи на те, що F # призначений лише для Microsoft, ви можете писати на перетині OCaml та F #, водночас отримуючи вигоду від середовища розробки F #. Це, безсумнівно, значно полегшить життя новачкові, якому доводиться битися із порівняно жахливими інструментами, доступними для SML та Haskell.
JD

1
Крім того, студентам може бути корисно мати ранні контакти з бібліотеками .NET. Швидше за все, вони все одно закінчуються на деяких роботах C # пізніше. Хоча насправді не вкладаючи багато коштів в альтернативи, просте програмування графічного інтерфейсу є плюсом для .NET (форм, wpf). Іноді все, що вам потрібно, це форма з полем для редагування та 2 кнопками ... За допомогою haskell я не міг би дати пораду "першого вибору", як це зробити. (Бібліотеки веб-сервера та html, можливо?).
BitTickler

4

Хаскелл. Я випереджаю в класі альго / теорії в CS завдяки матеріалам, які я навчився, використовуючи Haskell. Це настільки вичерпна мова, і вона навчить вас тонні CS, просто використовуючи її .

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

Тим не менш, більшість Haskell вивчали речі з менш наукових / математичних мов, таких як Ruby, ObjC або Python.

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