Подтвердить что ты не робот

Почему я не могу использовать селектора записей с экзистенциально квантифицированным типом?

При использовании типов Existential мы должны использовать синтаксис соответствия шаблону для извлечения значения forall ed. Мы не можем использовать обычные селектора записей в качестве функций. GHC сообщает об ошибке и предлагает использовать сопоставление с этим определением yALL:

{-# LANGUAGE ExistentialQuantification #-}

data ALL = forall a. Show a => ALL { theA :: a }
-- data ok

xALL :: ALL -> String
xALL (ALL a) = show a
-- pattern matching ok

-- ABOVE: heaven
-- BELOW: hell

yALL :: ALL -> String
yALL all = show $ theA all
-- record selector failed

forall.hs:11:19:
    Cannot use record selector `theA' as a function due to escaped type variables
    Probable fix: use pattern-matching syntax instead
    In the second argument of `($)', namely `theA all'
    In the expression: show $ theA all
    In an equation for `yALL': yALL all = show $ theA all

Некоторые мои данные занимают более 5 элементов. Трудно поддерживать код, если я используйте сопоставление с образцом:

func1 (BigData _ _ _ _ elemx _ _) = func2 elemx

Есть ли хороший способ сделать такой код поддерживаемым или обернуть его, чтобы я мог использовать какие-то селекторы?

4b9b3361

Ответ 1

Вы можете использовать синтаксис записи в соответствии с шаблоном,

func1 BigData{ someField = elemx } = func2 elemx

работает и гораздо меньше печатает для огромных типов.

Ответ 2

Экзистенциальные типы работают более тщательно, чем обычные типы. GHC (по праву) запрещает вам использовать theA как функцию. Но представьте, что такого запрета не было. Какой тип имел бы эта функция? Это должно быть примерно так:

-- Not a real type signature!
theA :: ALL -> t  -- for a fresh type t on each use of theA; t is an instance of Show

Чтобы выразить это очень грубо, forall заставляет GHC "забыть" тип аргументов конструктора; все, что знает система типов, это то, что этот тип является экземпляром Show. Поэтому, когда вы пытаетесь извлечь значение аргумента конструктора, нет способа восстановить исходный тип.

Что GHC делает за кулисами, так это то, что комментарий к поддельной сигнатуре типа выше - каждый раз, когда вы сопоставляете шаблон с конструктором ALL, переменной, привязанной к значению конструктора, присваивается уникальный тип, который гарантирован быть отличным от любого другого типа. Возьмем, к примеру, этот код:

case ALL "foo" of
    ALL x -> show x

Переменная x получает уникальный тип, который отличается от любого другого типа в программе и не может быть сопоставлен с любой переменной типа. Эти уникальные типы не позволяют выйти на верхний уровень, что является причиной того, что theA не может использоваться как функция.