Создает ли GHC новую копию объекта при деконструировании и восстановлении?
Если у меня есть тип типа data T = T Int String
и такая функция:
identity :: T -> T
identity (T a b) = T a b
После деконструкции в сопоставлении шаблонов GHC создает новый объект T, содержащий ссылки на те же Int и String? Или он возвращает тот же самый объект (с тем же адресом памяти), который он получил? Я понимаю, что они семантически эквивалентны, мне просто интересно.
Ответы
Ответ 1
В общем случае GHC будет выделять новое значение, а не повторно использовать аргумент в этой ситуации. В этом конкретном случае вы могли бы написать что-то вроде
f :: T -> T
f [email protected](T x y) = t
чтобы явно использовать аргумент. К сожалению, в одном из случаев, когда вы действительно этого хотите -
fmap :: (a -> b) -> Either e a -> Either e b
fmap f (Right x) = Right (f x)
fmap f (Left x) = Left x
- GHC будет выделять новое значение Left
, и вы не можете просто повторно использовать аргумент, потому что результат имеет другой тип. Насколько я знаю, нет способа сказать GHC повторно использовать аргумент в этом случае, кроме unsafeCoerce
.
Ответ 2
Вы можете проверить это достаточно легко с помощью -ddump-simpl
. Выделение значения ADT будет отображаться как приложение конструктора данных.
В этом случае GHC обнаруживает, что он может повторно использовать значение, и даже если ему не нужно выполнять сопоставление шаблонов:
module I where
data T = T Int String
identity :: T -> T
identity (T a b) = T a b
-
[email protected]:/tmp$ ghc -ddump-simpl I
[1 of 1] Compiling I ( I.hs, I.o )
==================== Tidy Core ====================
Result size of Tidy Core = {terms: 3, types: 3, coercions: 0}
I.identity :: I.T -> I.T
[GblId, Arity=1, Caf=NoCafRefs, Str=DmdType]
I.identity = \ (ds_dHN :: I.T) -> ds_dHN
Это происходит даже при включенной оптимизации, а также работает с ADT с несколькими конструкторами.