Критика OCaml: чи все-таки вона діє?


15

Я повний новачок із OCaml. Нещодавно я натрапив на цю сторінку, де перераховується велика кількість критики до OCaml.

Бачачи, що сторінка на ній досить стара (2007 р.): Яка з перелічених там пунктів відзначається і сьогодні? Наприклад: чи все ж правда, що неможливо надрукувати загальний об'єкт?

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


5
Я голосую, щоб закрити це питання поза темою, оскільки meta.programmers.stackexchange.com/questions/6417/…
Філіп

3
Існує розвилка , де ті , можливо , вже були виправлені: tryfsharp.org
Den

7
Звичайно, думка в тому есе, з яким ви пов’язані, є дійсним, але чи ці критика стосуються вас, це зовсім інша справа. Зауважте, що автор походить із загального Lisp-фону і тому має ліспійські значення. Якщо ви скористаєтесь іншим підходом до OCaml, ніж порівнювати його з Ліспом (наприклад, "OCaml - це Haskell для простих смертних" або "Якби C була функціональною мовою, ви мали б OCaml"), ви виявите це набагато сильніше. Незважаючи на всі вади, OCaml - це чудова мова, і я б закликав вас все-таки зайнятися цим.
амон

5
Наскільки я знаю, немає ніякого способу виявити переливання цілого числа в апаратному забезпеченні , тому вам потрібно буде вставити перевірки часу виконання, щоб його виявити всюди; але автор відхилив, використовуючи "bignum" на основі виконання! Скарга на статичний набір тексту означає, що ремені безпеки є поганими, оскільки ви можете подумати, що не можете загинути в автокатастрофі. Скарга на незмінність модуля говорить про те, що він хоче маніпулювати речами - антимодульна та схильна до помилок практика. "Зоопарк малого типу" не має нічого спільного з висновком типу. Зрозуміло, де лежать його упередження .
Довал

2
@Doval: Звичайно, ви можете виявити переповнення обладнання. Однак, це стосується програмного забезпечення.
Мейсон Уілер

Відповіді:


13

Ця стаття обговорюється в декількох місцях:

Підводячи підсумок: так, OCaml не є Lisp, і ні, він не є досконалим (що це означає?). Я не думаю, що моменти, згадані у публікації щоденника, є актуальними для щоденних програмістів O'Caml.

Вивчивши O'Caml, я думаю, що це цікава мова, яка може допомогти вам створити програми, про які ви навіть не зважилися б написати, скажімо, C / C ++ / Java: наприклад, подивіться на Frama-C .

Щодо оновленого опису O'Caml, я рекомендую вам ознайомитись з його особливостями : мова сприяє сильній техніці перевірки статичного типу, що дозволяє реалізаціям зосередитись на створенні ефективних, але безпечних, час виконання.

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

Статична перевірка типу

  • Помилкове почуття безпеки

    Це правда, але очевидно.

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

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

    Те саме стосується, наприклад, Common Lisp, але зворотно: динамічні типи по-перше, з необов'язковими деклараціями типів та директивами компілятора, другими.

  • Кілька основних типів

    Все ще застосовується: основна мова не змінилася (або не кардинально).

  • Мовчазне переповнення цілого числа

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

  • Незмінність модуля

    1. Автор згадує функціонерів, але я не розумію, як його приклад неможливо реалізувати. Читаючи розділ Модулі першого класу https://realworldocaml.org , здається, що модулі можна використовувати для складання та створення нових модулів. Звичайно, для зміни існуючого модуля потрібна модифікація вихідного коду, але знову ж таки, це не є незвичним серед мов програмування.

    2. " Семантично функції компілюються INLINE"

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

     let f x y = x + y ;;
     let g a b = f b a ;;
     let f x y = x * y ;;
     exit (g 2 3) ;;
    

    Вищеописана програма компілює, і коли вона виконується, повертає 5, тому що gвизначена в першій версії f, так само, як якщо функція виклику gвклала виклик у f. Це, до речі, не «погано», воно просто відповідає правилам тінізації імені О'Камла.

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

  • Поліморфізм викликає помилки типу виконання

    Я не можу відтворити згадану помилку. Я підозрюю, що це помилка компілятора.

Без макросів

Дійсно, макросів немає, але препроцесори (OcamlP4, OcamlP5, ...).

Незначення мови

  • Записати поле іменування пекла

    Щоправда, але ви повинні використовувати модулі:

    1. Два поля з двох записів мають однакову мітку в OCaml
    2. Розв’язування імен полів
  • Синтаксис

    Досі застосовується (але насправді це просто синтаксис).

  • Ніякого поліморфізму

    Все ще стосується, але якось є люди, які вважають за краще це замість числової вежі Ліспа (я не знаю чому). Я думаю, це допомагає при виведенні типу.

  • Невідповідні набори функцій

    Дивіться проект OCaml Battery Included . Зокрема, BatArray , як приклад map2масивів.

  • Немає динамічних змінних

    Можна реалізувати:

    1. http://okmij.org/ftp/ML/dynvar.txt
    2. http://okmij.org/ftp/ML/index.html#dynvar
  • Необов'язково ~ аргументи смоктати

    За обмеженням мови, ви не можете змішувати необов’язкові та ключові аргументи у загальному Lisp. Це означає, що це смокче? (Звичайно, це можна змінити за допомогою макросів (див., наприклад, мою відповідь )). Дивіться документацію O'Caml про необов'язкові та названі аргументи в O'Caml.

  • Часткова невідповідність додатку аргументу

    Я не думаю, що це насправді дратує на практиці.

  • Читання арифметики

    Це справедливо, але ви можете використовувати R або Python для числових проблем, якщо вам зручніше.

  • Мовчазне вирішення конфлікту імен

    Все ще стосується, але зауважте, що це добре документально підтверджено.

  • Немає об'єкта введення / виводу

    Досі застосовується.

Реалізація, бібліотеки

Вони щодня змінюються: остаточної відповіді немає.

Нарешті,

"Вам слід спробувати OCaml (або, ще краще, Haskell), навіть якщо ви думаєте, що це відстій, і ви не плануєте його використовувати. Без нього ваша освіта з інформатики неповна, як і неповна без деяких Lisp та C (або , ще краще, складання) експозиції. "

... все ще діє.


Дякую, я перегляну посилання, але я не дуже запитую, чи ці думки виправдані. Мене запитують, чи досі існують факти. Наприклад: чи є спосіб роздрукувати будь-який алгебраїчний тип даних? Чи все ще точно, що цілі числа переповнюються без попереджень? Чи існує сьогодні спосіб оперувати файлами та розпоряджатися ними, не пишучи кожен раз, коли коробчаста табличка має справу з закриттям файлів про помилки?
Андреа

@Andrea я відредагував свою відповідь.
coredump

1
"... Є люди, які вважають за краще це замість числової вежі Ліспа (я не знаю чому). Я вважаю, що це допомагає при виведенні типу." Бінго. Система типів SML та OCaml вимагає, щоб кожен вираз мав лише один тип. Перевантаження SML математичних операторів є винятком, вбудованим у мову. Це стосується і Haskell; Можливість такого типу перевантажень стала мотивацією класів типів. Суть полягає в тому, що ви можете мати лише один екземпляр класу типу на тип. Ви також не можете сліпо перетворити ціле число в поплавок однакового розміру - 64-бітний поплавок має лише 54 біти точності.
Довал

@Doval Що про щось на кшталт Набору цифрової вежі для Racket? Чи можемо ми уявити бібліотеку OCaml, яка б використовувала класи типів або Узагальнені типи алгебраїчних даних (GADT) для забезпечення поліморфних математичних операторів? Щодо перетворення: не всі операції можливі, але деякі є і можуть бути набрані.
coredump

2
@Doval: "Re: поліморфні математичні оператори, я не думаю, що немає способу без впровадження класів типів Haskell". F # має поліморфні математичні оператори без класів типів.
Джон Харроп

7

Бачачи, що сторінка на ній досить стара (2007 р.): Яка з перелічених там пунктів відзначається і сьогодні?

  • Помилкове почуття безпеки . Це нісенітниця.

  • Кілька основних типів . Тепер OCaml має байти та байтові масиви, але немає вбудованих рядків Unicode, 16-бітових цілих чисел, непідписаних цілих чисел, 32-бітових поплавків, векторів чи матриць. Деякі з них надають сторонні бібліотеки.

  • Мовчазне переповнення цілого числа . Без змін, але це ніколи не було проблемою.

  • Модуль Незмінність . Його рекомендація щодо того, що функції та модулі повинні бути незмінними, - це похмурий відкат Lisp і справді погана ідея. Ви можете замінити модулі, використовуючи, includeякщо хочете, але ви, звичайно, не можете їх вимкнути.

  • Поліморфізм викликає помилки типу виконання . Це велика проблема з OCaml, і вона не була виправлена. По мірі того, як ваші типи розвиваються в поліморфній рівності, порівняння та хеширование почнуть виходити з ладу, коли вони зустрінуть такі типи, як функції, і налагодження проблеми буде дуже важким. F # чудово вирішує цю проблему.

  • Немає Макроси . Як не дивно, коли він писав цей OCaml, фактично мав повну підтримку макросів, але вони вирішили витягнути цю функцію.

  • Обгортки . Це була справжня проблема, і вона не була виправлена. Досі не існує try ... finallyконструкції на мові OCaml, і жодної обгортки, що реалізує її в stdlib.

  • Місця . Без змін, але без проблем.

  • Записати поле іменування пекла . Правильно структуруйте свій код за допомогою модулів.

  • Синтаксис . Без змін, але без проблем.

  • Ніякого поліморфізму . Це були переважно дурниці, коли він це писав і нічого не змінилося.

  • Невідповідні набори функцій . OCaml все ще не має consфункції. Це чудово. Я не хочу, щоб слова Lisp були моєю мовою, дякую.

  • Немає динамічних змінних . Була гарна річ про OCaml. Все ще гарна річ про OCaml.

  • Необов'язково ~ аргументи смоктати . Необов’язкові аргументи рок. Я надавав значню Microsoft, щоб змусити їх додавати необов'язкові аргументи до F #.

  • Часткове невідповідність програми аргументу . Так?

  • Читання арифметики . Це змінилося з моменту припинення використання OCaml ~ 8 років тому. Мабуть, тепер ви можете це зробити Int64.((q * n - s * s) / (n - 1L)).

  • Мовчазне вирішення конфлікту імен . Він намагався зробити повноцінну розробку програмного забезпечення в системі REPL, як і в Lisp. Не робіть цього в OCaml. Використовуйте файли та компіляцію пакетів, використовуючи REPL лише для тестування, запуску одноразового коду та інтерактивних технічних обчислень.

  • Порядок оцінювання . Це було неправильно, коли він це писав. Порядок оцінювання не визначений в OCaml.

  • Немає об'єкта введення / виводу . Він посилався на сторонню бібліотеку, яка вже вирішила цю "проблему".

  • Компілятор зупиняється після першої помилки . Так?

  • Немає сліду стека для вбудованих виконуваних файлів . Виправлено.

  • Відладчик смокче . Я ніколи не використовував налагоджувач. Статична перевірка типу виявляє майже всі мої помилки.

  • GC смокче . Я виявив, що GC OCaml є чудовим за винятком однієї основної проблеми: глобальне блокування запобігає паралельному програмуванню.

  • Без неявних форвардних декларацій . Взаємна рекурсія явна за задумом у всіх МС. Єдина вірогідність полягає в тому, що typeвизначення за замовчуванням є рекурсивними, тоді як letприв'язки нерекурсивні за замовчуванням.

  • Функція раунду відсутня . У OCaml все ще є голі кістки stdlib, але сторонні бібліотеки, такі як Core Jane Jane's Core, надають roundдрузям.

  • Списки . List.mapдосі не є хвостовим рекурсивним. Я надсилав виправлення, щоб виправити подібні серйозні помилки, і довелося чекати років, перш ніж вони з’являться у випусках. Списки, звичайно, незмінні. І так вони повинні бути.

  • Швидкість . Я вважаю, що часи компіляції для великих поліморфних варіантів були встановлені.

  • Узгодження шаблону . Торжество надії на реальність. Спільнота Лісп цього не змогла. Звідси моє десяте правило: будь-яка досить складна програма Lisp містить спеціальну, неофіційну та неофіційну реалізацію половини компілятора шаблону відповідності шаблону OCaml.

Наприклад: чи все ж правда, що неможливо надрукувати загальний об'єкт?

Коли він написав, що ви не можете просто зробити:

print value

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


Зіставлення шаблонів: вихідний код OCaml та optima обидва посилання на один і той же папір: "Оптимізація відповідності шаблону". Я б сказав, що ні "ad-hoc", "bug-rid", ні "неофіційно вказані" тут реально не можуть бути застосовані. "F # має чудове рішення цієї проблеми": я щиро хотів би ознайомитися з цим трохи детальніше, якщо це можливо. Відповідь хороша, але прокляття, коли говорити про, consдає поганий тон (оригінальна стаття - це зухвала, але копіювати з неї не потрібно).
coredump

2
@coredump: "Я справді хотів би побачити трохи детальніше про це, якщо це можливо". F # має визначений користувачем спеціальний поліморфізм певних операторів і функцій. Таким чином, ви можете використовувати +int, floats та комплекси, але ви також можете визначити власні типи та додати перевантаження для +роботи над вашим типом. Це забезпечує стислість і читабельність Lisp або Haskell із передбачувано хорошими характеристиками SML або OCaml, досягаючи чогось, чого не робить жодна інша мова.
Джон Харроп,

@coredump: "Вихідний код OCaml та обидві посилання на один і той же папір". Методи, описані в цьому документі, повністю побудовані на системі типу ML. Система типів, яких у Ліспа немає. Optima не робить і не може зробити багато з того, що описано в цій роботі. Просто подивіться на розділ 4.2 "Використання інформації про вичерпність". Інформація про вичерпність у Lisp відсутня, оскільки не існує варіантів. Наприклад, OCaml вибирає між вкладеними стрибками або таблицею відправки на основі кількості листків, але ця інформація не відома в Lisp.
Джон Харроп

Lisp та OCaml призначені для різних речей (наприклад, динамізм, програмування на основі зображень). Але у Lisp є система типів, відмінна від Hindley-Milner, і реалізація не використовує її під час компіляції. Подивіться на цей сеанс SBCL з прикладами з розділу 4.2. Вичерпність вже перевіряється компілятором з виводу типу та декларацій. Optima може додати специфічний для впровадження код для макророзширення під час компіляції (або VCP SBCL), щоб мати інші стратегії, але недостатньо стимулів для цього.
coredump

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