Полиморфизм в OCaml - специальный, параметрический, включение / подтип
У меня проблемы с пониманием различных типов полиморфизма, особенно в отношении OCaml. Я понимаю, что полиморфизм допускает несколько типов в OCaml, обозначаемых как 'a, но я не понимаю, что такое различные типы полиморфизма.
Если бы кто-то мог дать мне объяснение на языке относительно низкого уровня, это было бы здорово! ad hoc, параметрический, включение / подтип
3 ответа
Вот приблизительное.
Специальный полиморфизм обычно относится к возможности объявить одно и то же имя (обычно функцию) разными типами, например + : int -> int -> int
а также + : float -> float -> float
в SML. Это разные функции, и они могут действовать совершенно по-разному, но компилятор или интерпретатор выбирает подходящую в зависимости от контекста. Я не могу вспомнить ни одного случая специального полиморфизма в OCaml. Это распространено в C++ и Java, однако.
Параметрический полиморфизм - это когда отдельная функция может работать с аргументом любого типа из-за того, что не пытается заглянуть в структуру этого аргумента. Например, cons : 'a -> 'a list -> 'a list
в состоянии добавить значение v
любого типа в список значений того же типа, потому что это не имеет значения для cons
какова структура (расположение) v
или какие операции он поддерживает. В терминах С, cons
не нужно "разыменовывать" указатель или выполнять какие-либо операции над v
это характерно для фактического типа v
, Обратите внимание, что в отличие от специального полиморфизма, cons
должен действовать одинаково для всех типов. Таким образом, параметрический и специальный полиморфизм являются в некотором роде естественными "противоположностями" друг друга. Параметрический полиморфизм ответственен за подавляющее большинство случаев полиморфизма в OCaml.
Подтип полиморфизма - это когда вы можете использовать значения типа t
где значения типа u
ожидаемые. Это может быть потому, что типа t
поддерживает все операции типа u
или потому что t
Здесь можно использовать структуру u
ожидается. Примерами этого могут быть подклассы (возможно, автобус может использоваться везде, где может автомобиль), или полиморфные варианты (вы можете использовать 'A | 'B
где 'A | 'B | 'C
ожидается).
РЕДАКТИРОВАТЬ за комментарий
Обратите внимание, однако, что подтип должен быть явно запрошен в OCaml. Если у вас есть, например, функция f : u -> int
и вы хотите применить его к v : t
где t
это подтип u
, ты должен написать f (v :> u)
, (v :> u)
синтаксис является приведением типа.
OCaml также поддерживает полиморфизм строк, который является формой параметрического полиморфизма с ограничениями. Если f
вместо f : #u -> int
(для типов объектов) или f : [< u] -> int
(для полиморфных вариантов) #u
/[< u]
синтаксис представляет переменную типа, аналогичную 'a
, но которые могут быть заменены только соответствующими "подтипами" u
(в ограниченном смысле, что они могут поддерживать больше полей / меньше конструкторов соответственно). Затем вы можете сделать f v
без принуждения. OCaml автоматически выводит типы, которые используют полиморфизм строк для многих выражений, включающих полиморфные варианты и объекты, но вы должны явно писать типы, если вы создаете подпись.
Есть еще способы использования и соображения для полиморфизма строк. Я пренебрег фактическими переменными строки и дополнительным синтаксисом и описал только то, что выглядит как ограниченное количественное определение (как в обобщениях Java). Более подробное и точное обсуждение полиморфизма строк, его названия и / или формализма, возможно, лучше сохранить для отдельных вопросов.
На самом деле я не думаю, что этот вопрос особенно подходит для сильных сторон переполнения стека. Есть целые книги, написанные о типах. На самом деле, я бы порекомендовал прочитать " Типы и языки программирования " Пирса, что показалось мне чрезвычайно полезным и восхитительным.
В качестве быстрого ответа (в основном на основе того, что я помню от Пирса:-), вот мое мнение об этих терминах.
Параметрический полиморфизм относится к типам со свободными переменными в них, где переменные могут быть заменены любым типом. Функция List.length
имеет такой тип, так как он может найти длину любого списка (независимо от типа элементов).
# List.length;;
- : 'a list -> int = <fun>
Одна из замечательных особенностей OCaml заключается в том, что он не только поддерживает такие типы, но и выводит их. Учитывая определение функции, OCaml выводит наиболее общий параметрически полиморфный тип для функции.
Подтипирование - это отношение между типами. Тип T является подтипом типа U, если все экземпляры T также являются экземплярами U (но не обязательно наоборот). OCaml поддерживает подтипы, то есть позволяет программе обрабатывать значение типа T как значение своего супертипа U. Тем не менее, программист должен просить об этом явно.
# type ab = [ `A | `B ];;
type ab = [ `A | `B ]
# type abc = [`A | `B | `C ];;
type abc = [ `A | `B | `C ]
# let x : ab = `A;;
val x : ab = `A
# let y : abc = x;;
Error: This expression has type ab but an expression was expected
of type abc. The first variant type does not allow tag(s) `C
# let y : abc = (x :> abc);;
val y : abc = `A
В этом примере введите type ab
это подтип типа abc
, а также x
имеет тип ab
, Ты можешь использовать x
как значение с типом abc
, но вы должны явно конвертировать, используя :>
оператор типа.
Специальный полиморфизм относится к полиморфизму, который определяется программистом для конкретных случаев, а не выводится из фундаментальных принципов. (Или, по крайней мере, это то, что я имею в виду, возможно, другие люди используют термин по-другому.) Возможным примером этого является иерархия наследования ОО, где фактические типы состояния объекта не должны быть связаны каким-либо образом, пока методы имеют правильные отношения.
Ключевое замечание о специальном полиморфизме (IMHO) заключается в том, что программист должен заставить его работать. Следовательно, это не всегда работает. Другие типы полиморфизма, основанные на фундаментальных принципах, на самом деле не могут не работать. Это утешительное чувство при работе со сложными системами.
Идентичность полиморфна:
# let ident x = x;;
val ident : 'a -> 'a = <fun>
# ident 1;;
- : int = 1
# ident "ok";;
- : string = "ok"
# ident [];;
- : 'a list = []
# ident List.length;;
- : '_a list -> int = <fun>
# ident ident;;
- : '_a -> '_a = <fun>
сложить также:
# open List;;
# fold_left (+) 0 [1;2;3];;
- : int = 6
# fold_left (^) "" ["1";"2";"3"];;
- : string = "123"
# fold_left (fun a (x,y) -> a+x*y) 0 [(1,2);(3,4);(5,6)];;
- : int = 44