Критика OCaml: это все еще верно?

15

Я полный новичок с OCaml. Недавно я наткнулся на эту страницу со списком критических замечаний по отношению к OCaml.

Видя, что эта страница довольно старая (2007 год): какие из перечисленных здесь пунктов пули все еще актуальны сегодня? Например: все еще верно, что невозможно напечатать универсальный объект?

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

Andrea
источник
5
Я голосую,
Филипп
3
Есть развилка, где они могли бы быть исправлены: tryfsharp.org
Den
7
Конечно, мнение в том эссе, на которое вы ссылаетесь, является верным, но вопрос о том, относится ли эта критика к вам, совершенно другой вопрос. Обратите внимание, что автор происходит из фона Common Lisp и поэтому имеет значения Lispish. Если вы выберете другой подход к OCaml, нежели сравниваете его с Lisp (например, «OCaml - это Haskell для простых смертных» или «Если бы C был функциональным языком, у вас был бы OCaml»), вы найдете его гораздо более удовлетворительным. Несмотря на все недостатки, OCaml - отличный язык, и я бы посоветовал вам все же побаловаться с ним.
Амон
5
Насколько я знаю, нет способа обнаружить целочисленное переполнение в оборудовании , поэтому вам нужно было бы вставлять проверки во время выполнения повсеместно, чтобы обнаружить его; но автор отклонил использование "bignum" на основе производительности! Жалоба на статическую типизацию сводится к тому, что ремни безопасности плохие, потому что вы можете подумать, что не можете умереть в автомобильной аварии. Жалоба на неизменяемость модулей говорит о том, что он хочет запутаться - антимодульная и подверженная ошибкам практика. «Маленький тип зоопарк» не имеет никакого отношения к выводу типа. Понятно, где лежат его предубеждения .
Довал
2
@Doval: Конечно, вы можете обнаружить переполнение аппаратного обеспечения. Однако иметь дело с этим программным вопросом.
Мейсон Уилер

Ответы:

13

Эта статья обсуждается в нескольких местах:

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

Изучив O'Caml, я думаю, что это интересный язык, который может помочь вам создавать программы, на которые вы даже не посмели бы писать, скажем, на C / C ++ / Java: например, взглянуть на Frama-C .

Чтобы получить более свежее описание O'Caml, я рекомендую вам прочитать о его возможностях : язык поддерживает строгие статические методы проверки типов, которые позволяют реализациям сосредоточиться на создании производительных, но безопасных сред выполнения.

Важно : я не эксперт OCaml: если вы один из них и видите, что я написал что-то ужасно неправильно, пожалуйста, исправьте меня. Я буду редактировать этот пост соответственно.

Проверка статического типа

  • Ложное чувство безопасности

    Это правда, но очевидно.

    Статическая типизация дает вам доказательства того, что вы можете доверять подмножеству свойств вашей программы. Если вы не согласитесь пройти все формально, обычная (не игрушка) программа будет подвержена ошибкам программирования, которые могут быть обнаружены только во время выполнения.

    Именно тогда могут применяться методы динамической проверки: у компилятора OCaml есть флаги для генерации исполняемых файлов с отладочной информацией и т. Д. Или он может генерировать код, который слепо доверяет программисту и максимально стирает информацию о типах. Программисты, которым нужны надежные программы, должны явно выполнять динамические проверки.

    То же самое относится, например, к Common Lisp, но наоборот: сначала динамические типы, а затем необязательные объявления типов и директивы компилятора.

  • Несколько основных типов

    Все еще применяется: основной язык не изменился (или не сильно).

  • Silent Integer Overflow

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

  • Модуль неизменяемости

    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, ...).

Незначительная языковая Suckiness

  • Запись поля именования ада

    Правда, но вы должны использовать модули:

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

    Все еще применяется (но на самом деле, это всего лишь синтаксис).

  • Нет полиморфизма

    Все еще применяется, но почему-то есть люди, которые предпочитают это вместо числовой башни Лиспа (я не знаю почему). Я полагаю, это помогает с выводом типа.

  • Несовместимые наборы функций

    См. Проект « Аккумуляторы OCaml включены ». В частности, BatArray , для примера map2для массивов.

  • Нет динамических переменных

    Может быть реализовано:

    1. http://okmij.org/ftp/ML/dynvar.txt
    2. http://okmij.org/ftp/ML/index.html#dynvar
  • Необязательные аргументы ~ отстой

    По языковым ограничениям в Common Lisp нельзя смешивать необязательные аргументы и аргументы с ключевыми словами. Значит ли это, что это отстой? (конечно, это можно изменить с помощью макросов (см., например, мой ответ )). См. Документацию O'Caml для дополнительных и именованных аргументов в O'Caml.

  • Частичное несоответствие приложения аргументу

    Я не думаю, что это действительно раздражает на практике.

  • Читаемость арифметики

    Это верно, но вы можете использовать R или Python для численных задач, если хотите.

  • Бесшумное разрешение конфликтов имен

    Все еще применяется, но обратите внимание, что это хорошо задокументировано.

  • Нет ввода / вывода объекта

    Все еще применяется.

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

Они постоянно меняются каждый день: однозначного ответа нет.

В заключение,

«Вы должны попробовать OCaml (или, еще лучше, Haskell), даже если вы думаете, что это отстой, и вы не планируете его использовать. Без него ваше образование в области компьютерных наук будет неполным, как и неполное без некоторых Lisp и C (или , еще лучше, сборка) помещения. "

... все еще применяется.

CoreDump
источник
Спасибо, я посмотрю ссылки, но я не спрашиваю, оправданы ли эти мнения. Я спрашиваю, сохраняются ли факты. Например: есть ли способ распечатать любой алгебраический тип данных? Все еще верно, что целые числа переполняются без предупреждений? Есть ли сегодня способ работать с файлами и распоряжаться ими без необходимости каждый раз записывать шаблон для обработки закрытых файлов при ошибках?
Андреа
@ Андреа я отредактировал свой ответ.
coredump
1
«... есть люди, которые предпочитают это вместо числовой башни Лиспа (я не знаю почему). Я полагаю, это помогает с выводом типа». Бинго. Система типов SML и OCaml требует, чтобы каждое выражение имело только один тип. Перегрузка математических операторов в SML является исключением, встроенным в язык. Это верно и для Хаскелла; включение такого рода перегрузки было мотивом для классов типов. Уловка в том, что вы можете иметь только один экземпляр класса типа для каждого типа. Вы также не можете слепо преобразовать целое число в число с плавающей точкой одинакового размера - 64-разрядное число с плавающей точкой имеет только 54 бита точности.
Довал
@Doval А как насчет набора числовой башни для ракетки? Можем ли мы представить библиотеку OCaml, которая использовала бы классы типов или Обобщенные алгебраические типы данных (GADT) для обеспечения полиморфных математических операторов? Что касается преобразования: не все операции возможны, но некоторые из них могут и могли быть напечатаны.
coredump
2
@Doval: «Re: полиморфные математические операторы, я не думаю, что есть какой-либо способ без реализации классов типов Haskell». F # имеет полиморфные математические операторы без классов типов.
Джон Харроп
7

Видя, что эта страница довольно старая (2007 год): какие из перечисленных здесь пунктов пули все еще актуальны сегодня?

  • Ложное чувство безопасности . Это нонсенс.

  • Несколько основных типов . В OCaml теперь есть байты и байтовые массивы, но нет встроенных юникодных строк, 16-битных целых, беззнаковых целых, 32-битных чисел с плавающей точкой, векторов или матриц. Сторонние библиотеки предоставляют некоторые из них.

  • Silent Integer Overflow . Без изменений, но это никогда не было проблемой.

  • Неизменность модуля . Его рекомендация, что функции и модули должны быть изменяемыми, является мрачным возвратом к Lisp и действительно плохой идеей. Вы можете заменить модули, используя, includeесли хотите, но, конечно, не можете изменять их.

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

  • Нет макросов . По иронии судьбы, когда он писал этот OCaml, он полностью поддерживал макросы, но теперь они решили использовать эту функцию.

  • Упаковщики . Это была настоящая проблема, и она не была исправлена. В try ... finallyязыке OCaml до сих пор нет конструкции и нет оболочки, реализующей ее в stdlib.

  • Места . Без изменений, но не проблема.

  • Запись поля именования ада . Структурируйте свой код правильно, используя модули.

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

  • Полиморфизма нет . В основном это была ерунда, когда он это написал, и ничего не изменилось.

  • Несовместимые наборы функций . OCaml до сих пор не имеет consфункции. Все в порядке. Я не хочу, чтобы Лисп на моем языке, спасибо.

  • Нет динамических переменных . Была хорошая вещь об OCaml. Все еще хорошая вещь об OCaml.

  • Необязательные аргументы ~ отстой . Необязательные аргументы рок. Я подписал Microsoft, чтобы они добавили необязательные аргументы в F #.

  • Частичное несоответствие приложения аргументу . А?

  • Читаемость арифметики . Это изменилось с тех пор, как я перестал использовать OCaml ~ 8 лет назад. Видимо, теперь вы можете сделать Int64.((q * n - s * s) / (n - 1L)).

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

  • Порядок оценки . Это было неправильно, когда он написал это. Порядок оценки не определен в OCaml.

  • Нет ввода / вывода объекта . Он привел стороннюю библиотеку, которая уже решила эту «проблему».

  • Компилятор останавливается после первой ошибки . А?

  • Нет трассировки стека для изначально скомпилированных исполняемых файлов . Исправлена.

  • Отладчик отстой . Я никогда не использовал отладчик. Статическая проверка типов ловит почти все мои ошибки.

  • GC отстой . Я нашел GC OCaml превосходным, за исключением одной главной проблемы: глобальная блокировка предотвращает параллельное программирование.

  • Нет неявных предварительных объявлений . Взаимная рекурсия явно предусмотрена во всех ML. Единственным недостатком является то, что typeопределения являются рекурсивными по умолчанию, тогда как letпривязки не являются рекурсивными по умолчанию.

  • Функция обхода отсутствует . В OCaml все еще есть простой stdlib, но сторонние библиотеки, такие как Jane St's Core roundи друзья.

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

  • Скорость . Я считаю, что время компиляции для больших полиморфных вариантов было исправлено.

  • Сопоставление с образцом . Торжество надежды над реальностью. Сообществу Lisp не удалось этого сделать. Отсюда мое 10-е правило: любая достаточно сложная программа на Лиспе содержит специальную, неофициально заданную и ошибочную реализацию половины компилятора сопоставления с образцами OCaml.

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

Когда он написал, что вы не могли просто сделать:

print value

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

Джон Харроп
источник
Сопоставление с образцом: исходный код OCaml и optima ссылаются на одну и ту же статью: «Оптимизация сопоставления с образцом». Я бы сказал, что ни «ad-hoc», ни «ошибочные», ни «неофициально определенные» здесь реально не применимы. «У F # есть отличное решение этой проблемы»: я искренне хотел бы видеть немного больше подробностей об этом, если это возможно. Ответ хороший, но ругательство при разговоре consдает плохой тон (оригинальная статья напыщенная, но вам не нужно ее копировать).
coredump
2
@coredump: «Я искренне хотел бы увидеть немного больше информации об этом, если это возможно». F # имеет определенный пользователем полиморфизм для определенных операторов и функций. Таким образом, вы можете использовать +ints, float и complex, но вы также можете определить свои собственные типы и добавить перегрузку для +работы с вашим типом. Это обеспечивает краткость и удобочитаемость Lisp или Haskell с предсказуемо хорошей производительностью SML или OCaml, достигая того, чего не делает ни один другой язык.
Джон Харроп
@coredump: «Исходный код OCaml и optima ссылаются на одну и ту же статью». Методы, описанные в этой статье, полностью основаны на системе типов ML. Система типов, которой нет в Лиспе. Optima не делает и не может сделать многое из того, что описано в этой статье. Просто посмотрите на раздел 4.2 «Использование исчерпывающей информации». В Лиспе нет исчерпывающей информации, потому что нет вариантов типов. Например, OCaml выбирает между вложенными переходами или таблицей диспетчеризации на основе количества листьев, но эта информация неизвестна в Лиспе.
Джон Харроп
Lisp и OCaml предназначены для разных целей (например, динамизм, программирование на основе изображений). Но Lisp имеет типовую систему, отличную от Хиндли-Милнера, и реализация этого использовать его во время компиляции. Посмотрите на эту сессию SBCL с примерами из раздела 4.2 статьи. Полнота уже проверена компилятором из вывода типа и объявлений. Optima могла бы добавить специфичный для реализации код для макроразложения во время компиляции (или SOPL VOP), чтобы иметь другие стратегии, но стимулов для этого недостаточно.
coredump
Как это относится к пользовательскому алгебраическому типу данных?
Джон Харроп