Это связано с изменчивостью.
Рассмотрим этот фрагмент:
type T<'a> = { mutable x : 'a option }
let t = { x = None }
Тип t
равен T<'a>
, то есть t
является общим c, он имеет универсальный c параметр 'a
, означающий, что t.x
может быть любого типа - независимо от того, что выберет потребитель.
Затем, предположим, в одной части программы, которую вы делаете:
t.x <- Some 42
Совершенно законно: при доступе к t
вы выбираете 'a = int
, а затем t.x : int option
, так что вы можете вставить sh Some 42
в него.
Затем, предположим, в другой части вашей программы вы делаете:
t.x <- Some "foo"
О нет, что происходит сейчас? t.x : int option
или string option
? Если компилятор добросовестно скомпилирует ваш код, это приведет к повреждению данных. Так что компилятор отказывается, на всякий случай.
Так как в общем случае компилятор не может действительно проверить, есть ли что-то изменчивое глубоко внутри вашего типа, он принимает безопасный маршрут и отклоняет значения (что означает «не функции») предполагается, что они являются обобщенными c.
Обратите внимание, что это относится к syntacti c значениям, а не логическим . Даже если ваше значение действительно является функцией, но синтаксически не определяется как таковое (то есть не имеет параметров), ограничение по-прежнему применяется. В качестве иллюстрации рассмотрим следующее:
type T<'a> = { mutable x : 'a option }
let f t x =
t.x <- Some x
let g = f { x = None }
Здесь, хотя g
действительно функция, ограничение работает точно так же, как в моем первом примере выше: каждый вызов g
пытается работать с тем же родовым значением c значение T<'a>
В некоторых более простых случаях компилятор может использовать ярлык. Так, например, одна эта строка не компилируется:
let f = List.map id
Но эти две строки делают:
let f = List.map id
let x = f [1;2;3]
Это потому, что вторая строка позволяет компилятору выводить, что f : list int -> list int
, поэтому параметр generi c исчезает, и все счастливы.
На практике оказывается, что этот ярлык охватывает подавляющее большинство случаев. Единственный раз, когда вы действительно сталкиваетесь с ограничением значения, это когда вы пытаетесь экспортировать такое значение generi c из модуля.
В Haskell вся эта ситуация не ' этого не происходит, потому что Haskell не допускает мутации. Все просто.
Но опять же, хотя Haskell не допускает мутации, это своего рода сорта - через unsafePerformIO
. И угадайте, что - в этом сценарии вы рискуете столкнуться с той же проблемой. Это даже , упомянутое в документации .
За исключением GH C не отказывается от его компиляции - в конце концов, если вы используете unsafePerformIO
, вы должны знать, что делаете. Правильно? : -)