Ответ 1
Полиморфизм строк является одной из форм полиморфизма. OCaml предоставляет два вида полиморфизма - параметрические и рядные, а также отсутствие двух других - ad hoc и включение (aka subtyping) 1.
Прежде всего, что такое полиморфизм? В контексте систем типов полиморфизм позволяет одному термину иметь несколько типов. Проблема здесь в том, что сам тип слова сильно перегружен в сообществе компьютерных наук и программирования. Поэтому, чтобы свести к минимуму путаницу, позвольте просто снова ввести его здесь, чтобы быть на одной странице 2. Тип термина обычно обозначает некоторую аппроксимацию семантики. Там, где семантика может быть такой же простой, как набор значений, оснащенных набором операций или чем-то более сложным, например эффектами, аннотациями и произвольными теориями. В общем, семантика обозначает множество всех возможных поведений члена. Система типов обозначает набор правил, который допускает некоторые языковые конструкции и запрещает другие на основе их типов. I.e., он проверяет правильность составов терминов. Например, если на языке существует конструктор приложения-функции, система типов будет использовать приложение только для тех аргументов, которые имеют типы, соответствующие типам параметров. И то, где полиморфизм вступает в игру. В системах с мономорфным типом это совпадение может быть только один к одному, т.е. Буквальный. Полиморфные системы предоставляют механизмы для указания некоторого регулярного выражения, которое будет соответствовать семейству типов. Таким образом, различные виды полиморфизма - это просто разные типы регулярных выражений, которые вы можете использовать для обозначения семейства типов.
Теперь рассмотрим различные виды полиморфизма с этой точки зрения. Например, параметрический полиморфизм подобен точке в регулярных выражениях. Например, 'a list
- . list
- это означает, что мы точно сопоставляем list
, а параметр типа list
может быть любым типом. Полиморфизм строк является оператором звезды, например, <quacks : unit; ..>
является таким же, как <quacks : unit; .*>
. И это означает, что он соответствует любому типу, который quacks
и делает что-то еще 3. Говоря об номинальном подтипинге, в этом случае у нас есть номинальные классы (классы символов в регулярном выражении), и мы указываем семейство типов с именем их базового класса. Например, duck
выглядит как [:duck:]*
, и любое значение, которое правильно зарегистрировано как член класса, совпадает с этим типом (через наследование класса и новый оператор) 4. Наконец, ad-hoc-полиморфизм на самом деле также является номинальным и сопоставляет классы символов в регулярных выражениях. Основное различие здесь заключается в том, что понятие типа в ad-hoc-полиморфизме применяется не к значению, а скорее к названию. Таким образом, имя, например имя функции или оператор +
, может иметь несколько определений (реализаций), которые должны быть статически зарегистрированы с использованием какого-либо языкового механизма (например, перегрузка оператора, реализация метода и т.д.). Таким образом, ad-hoc-полиморфизм является лишь особым случаем номинального подтипирования.
Теперь, когда мы понятны, мы можем обсудить, что дает нам полиморфизм строк. Полиморфизм строк также известен как структурный подтипирование и утиная типизация. В общем, как мы обсуждали выше, это позволяет нам указывать тип как "что-либо, что может помешать", а не "что-либо, что реализует интерфейс IDuck". Итак, вы можете, конечно, сделать то же самое с номинальной типизацией, указав интерфейс утки и явно зарегистрировать все реализации как экземпляры этого интерфейса, используя некоторые механизмы inherit
или implements
. Но главная проблема здесь в том, что ваша иерархия запечатана, т.е. Вам нужно изменить свой код для регистрации реализации во вновь создаваемом интерфейсе. Это нарушает принцип открытия/закрытия и затрудняет повторное использование кода. Еще одна проблема с номинальным подтипированием заключается в том, что, если ваша иерархия не образует решетку (т.е. Для любых двух классов всегда существует минимальная верхняя граница), вы не можете реализовать вывод типа на нем 5.
1) Однако OCaml предоставляет классы с наследованием и понятием подтипа, он по-прежнему не является подтиповым полиморфизмом в соответствии с общим определением, поскольку он не является номинальным. Из оставшейся части ответа должно быть ясно.
2) Я просто фиксирую терминологию, я не утверждаю, что мое определение правильное. Многие люди думают, что тип обозначает представление значения, и исторически это правильно.
3) Возможно, лучшее регулярное выражение будет <.*; quacks : unit; .*>
, но я думаю, что у вас есть идея.
4)Таким образом, OCaml не имеет подтипирования полиморфизма, хотя имеет понятие подтипа. Когда вы укажете тип, он не будет соответствовать подтипу, он будет соответствовать только буквально, и вам нужно использовать явный оператор повышения, чтобы значение типа T применимо в контексте, где ожидается super(T)
. Итак, хотя в OCaml есть подтипирование, это не о полиморфизме.
5) И хотя требование решетки не выглядит невозможным, в реальной жизни трудно навязывать это ограничение на иерархии, или если оно наложено, точность вывода типа всегда будет связанных с точностью иерархии типов. Так что на практике это не работает, ср. Scala