Определение ограниченного подмножества Storable для соответствия типов - PullRequest
3 голосов
/ 07 февраля 2012

Я получаю сообщение об ошибке для кода ниже - я подозреваю, что это связано с сигнатурой типа функции dispatch, которая возвращает Vector типа Storable a. Какой простой способ обновить dispatch подпись типа функции, чтобы сделать только Int32 и CChar в подписи типа:

{-#  LANGUAGE BangPatterns #-}
import Data.Vector.Storable as SV
import Foreign.C.Types (CChar)
import GHC.Int (Int32)

data AList = I {-# UNPACK #-} !(SV.Vector Int32)
              | S {-# UNPACK #-} !(SV.Vector CChar)


dispatch :: (Storable a) => AList -> SV.Vector a
dispatch (I x) = x
dispatch (S x) = x

Ошибка в ghci 7.4.1:

    test.hs:11:18:
    Couldn't match type `CChar' with `Int32'
    Expected type: Vector a
      Actual type: Vector Int32
    In the expression: x
    In an equation for `dispatch': dispatch (I x) = x
Failed, modules loaded: none.

Я задаю этот вопрос, предполагая, что мой диагноз ошибки верен. Если мой диагноз неверен, я буду признателен за указания о том, как исправить ошибку выше.

1 Ответ

5 голосов
/ 07 февраля 2012

Подпись типа

dispatch :: (Storable a) => AList -> SV.Vector a

гласит «дай мне AList, и я дам тебе SV.Vector a для любого a, сколько хочешь, так долго»как это экземпляр Storable ".Это не правильно!Для любого заданного значения вы можете указать только один a, и вы выберите его, а не код вызова.Проблема может быть легче увидеть, если вы явно добавите квантификатор:

dispatch :: forall a. (Storable a) => AList -> SV.Vector a

Что вы действительно хотите сказать, это «дайте мне AList, и я дам вам SV.Vector a для некоторые a, которые я выберу, но я обещаю, что это будет экземпляр Storable ".Для этого нам понадобится экзистенциальный тип:

data SomeSVVector = forall a. (Storable a) => SomeSVVector (SV.Vector a)

dispatch :: AList -> SomeSVVector
dispatch (I x) = SomeSVVector x
dispatch (S x) = SomeSVVector x

(для этого вам понадобится {-# LANGUAGE ExistentialQuantification #-}.)

Это дает SomeVVector тип:

SomeVVector :: (Storable a) => SV.Vector a -> SomeVVector

Затем можно вывести SV.Vector из результата dispatch с помощью case dispatch x of SomeSVVector vec -> ....Тем не менее, это, вероятно, не так уж и полезно: поскольку экзистенциал может содержать вектор с элементами любого экземпляра Storable, операции only , которые вы сможете выполнитьна данных внутри те, которые предлагаются Storable класса.Если вы хотите что-то, что пользовательский код может анализировать и «отправлять» по типу, вам понадобится теговое объединение - это именно то, что ваш AList тип уже имеет.

Если вы действительно хотите перейтивниз по экзистенциальному маршруту, тогда я бы предложил определить свой собственный класс типов как подкласс Storable, который содержит все операции, которые вы, возможно, захотите выполнить над значениями внутри.По крайней мере, вы, вероятно, захотите добавить Integral к ограничению SomeSVVector.


Как вы упоминали в комментариях, если вы не возражаете против AList изInt32 с и AList из CChar с разными типами, вы можете использовать GADT:

data AList a where
  I :: {-# UNPACK #-} !(SV.Vector Int32) -> AList Int32
  S :: {-# UNPACK #-} !(SV.Vector CChar) -> AList CChar

dispatch :: AList a -> SV.Vector a
dispatch (I x) = x
dispatch (S x) = x

Здесь AList по сути является версией SV.Vector, которая работает только наопределенные типы элементов.Однако dispatch на самом деле не так уж полезен - нет реального способа «вернуться» к AList после того, как вы вынули его с помощью dispatch, потому что предложения по сопоставлению с образцом GADT для унификации типов работают только с явное сопоставление с образцом;Вы не можете сказать, что результатом dispatch является SV.Vector Int32 или SV.Vector CChar.Что-то вроде

dispatch :: (SV.Vector Int32 -> r) -> (SV.Vector CChar -> r) -> AList a -> r

будет работать, но это эквивалентно (и более неудобно, чем) сопоставлению с образцом в вашей оригинальной версии с тегами union.

Не думаю, что есть разумный способопределить полезное dispatch;Я бы предложил использовать явное сопоставление с образцом в исходном определении AList.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...