После написания этого куска кодаOCaml дисперсии (+ 'а, -'a) и инвариантность
module type TS = sig
type +'a t
end
module T : TS = struct
type 'a t = {info : 'a list}
end
я понял, что нужно, чтобы info
быть изменяемыми.
я писал тогда:
module type TS = sig
type +'a t
end
module T : TS = struct
type 'a t = {mutable info : 'a list}
end
Но, удивительно,
Type declarations do not match:
type 'a t = { mutable info : 'a list; }
is not included in
type +'a t
Their variances do not agree.
О, я помню о дисперсии. Это было что-то около covariance и contravвариантность. Я храбрый человек, я узнаю о своей проблеме в одиночку!
Я нашел эти две интересные статьи (here и here), и я понял!
Я могу написать
module type TS = sig
type (-'a, +'b) t
end
module T : TS = struct
type ('a, 'b) t = 'a -> 'b
end
Но потом я подумал. Как получилось, что mutable datatypes являются инвариантными, а не только ковариантными?
Я понимаю, что 'A list
можно рассматривать как подтип ('A | 'B) list
, потому что мой список не может измениться. То же самое для функции, если у меня есть функция типа 'A | 'B -> 'C
, ее можно рассматривать как подтип функции типа 'A -> 'C | 'D
, потому что если моя функция может обрабатывать 'A
и 'B
, она может обрабатывать только 'A
и если я только вернусь 'C
Я могу с уверенностью ожидать 'C
или 'D
(но я получу только 'C
).
Но для массива? Если у меня есть 'A array
, я не могу считать его ('A | 'B) array
, потому что если я изменяю элемент в массиве, помещающий 'B
, тогда мой тип массива неверен, потому что это действительно ('A | 'B) array
, а не 'A array
. Но как насчет ('A | 'B) array
как 'A array
. Да, было бы странно, потому что мой массив может содержать 'B
, но странно я думал, что это то же самое, что и функция. Может быть, в конце концов, я не все понял, но я хотел рассказать о нем здесь, потому что мне потребовалось много времени, чтобы понять это.
TL; DR:
настойчивые:
+'a
функции:
-'a
изменяемые: инвариант (
'a
)? Почему я не могу заставить его быть-'a
?
Именно такой ответ я ожидал, поэтому этот пост может помочь будущим разработчикам OCaml легко и быстро понять эту проблему. – Lhooq
Я думаю, что вы имели в виду «и setter * как тип ...» - отправили править, надеюсь, что я не понял, что исправить неправильно! На самом деле наткнулся на это несколько минут. – ELLIOTTCABLE
да, определенно :) Спасибо! – ivg