У меня есть тип данных
newtype Zq q = Zq (IntType q)
где 'q' будет экземпляром класса
class Foo a where
type IntType a
а «IntType» — это просто базовое представление (, т. е. Int, Integral и т. д. ), связанное с «q».
Я хочу сделать Zq экземпляром Data.Vector.Unbox . В настоящее время мы вручную создаем Unbox, используя около 50 строк тривиального кода, как это предлагается по ссылке выше. В нашем коде мы будем создавать несколько разных типов Unbox, поэтому писать по 50 строк для каждого типа не очень привлекательно.
Я нашел две альтернативы здесь . Одним из вариантов является использование этого пакета , который использует Template Haskell для создания экземпляров Unbox. Код TH будет выглядеть как:
derivingUnbox "Zq"
[d| instance (Foo q, U.Unbox (IntType q)) => Unbox' (ZqBasic q) (IntType q) |]
[| \ (Zq x) -> x |]
[| \ x -> Zq x |]
Проблема в том, что я не могу определить экземпляры, используя синонимы связанных типов(или можно??)
[Связанный вопрос :Почему TypeSynonymInstances , расширение, подразумеваемое FlexibleInstances, не позволяет ассоциированным экземплярам синонимов типов? Это как-то принципиально другой зверь?]
Мое текущее решение этой проблемы состоит в том, чтобы переопределить Zq как
newtype Zq q i = Zq i
а затем добавьте ограничение равенства
i~(IntType q)
в каждом случае с участием (Zq q i ), что не очень элегантно. Мой (рабочий )вывод Unbox становится
derivingUnbox "Zq"
[d| instance (U.Unbox i, i~IntType q, Foo q) => Unbox' (Zq q i) i |]
[| \ (Zq x) -> x |]
[| \ x -> Zq x |]
Я чувствую, что должен быть в состоянии выполнить это, не прибегая к явному раскрытию типа «i». Все, что я сделал, это переместил его из синонима связанного типа в явный параметр с ограничениями равенства. Почему это «фундаментально» другой (и, по-видимому, более безопасный )подход? Есть ли способ избежать добавления параметра типа «i» и при этом получить автоматический вывод Unbox?
Помимо дополнительного параметра типа, у меня возникли проблемы с использованием пакета TH для получения Unbox для (Vector r ), то есть я хочу создать Unbox Vector из Unbox Vectors. Моя попытка что-то вроде:
newtype Bar r = Bar (Vector r)
derivingUnbox "Bar"
[d| instance (Unbox r) => Unbox' (Bar r) (Vector r) |]
[| \ (Bar x) -> x |]
[| \ x -> Bar x |]
но я получаю (множество )ошибок типа:
`basicUnsafeFreeze` is not a (visible) method of class `Data.Vector.Generic.Base.Vector`
Я не уверен, почему он не может найти этот метод, когда он отлично работает для моего типа Zq.
Второй подход, указанный выше , использует расширение GeneralizedNewtypeDeriving. Самая большая проблема, которую я вижу с этим подходом, заключается в том, что у меня есть некоторые фактические данные (, а не Newtype ), которые мне нужно распаковать. Однако, просто используя расширение, я должен написать
newtype Zq q = Zq (IntType q) deriving (Unbox, M.MVector MVector, G.Vector Vector)
или хотя бы
newtype Zq q i = Zq i deriving (Unbox, M.MVector MVector, G.Vector Vector)
Первый приводит к ошибкам:
No instance for (Unbox (IntType q)) arising from the `deriving` clause of a data type declaration
No instance for (M.MVector MVector (IntType q)) ""
No instance for (G.Vector Vector (IntType q)) ""
а второй дает:
No instance for (M.MVector MVector i) ""
No instance for (G.Vector U.Vector i) ""
Я не уверен, почему он не может получить эти экземпляры, поскольку сообщение выше заставляет меня поверить, что это должно быть возможно. Возможно, мне сойдет с рук использование синонима связанного типа с GeneralizedNewtypeDeriving? (Это по-прежнему (, вероятно, )не решает мою проблему, когда мне нужно получить Unbox для 'data's.)
Спасибо за вашу помощь!