Упаковка значения в экзистенциальный тип, зная только класс типа
В дополнение к моей цели по сокращению шаблона, необходимого для использования Haxl с реляционной базой данных, я пытаюсь упаковать результат необработанного запроса SQL через Persistent в экзистенциально количественно выраженный тип. Однако проверка типов не позволит этого:
data SomeRawSql where
SomeRawSql :: forall b. RawSql b => [b] -> SomeRawSql
packedVal = let res = runDB $ rawSql "SELECT * FROM ..." [toPersistValue (pack "ABC")]
in fmap SomeRawSql res
Это приводит к ошибке типа в строке с fmap: Ambiguous type variable ‘b0’ arising from a use of ‘SomeRawSql’ prevents the constraint ‘(RawSql b0)’ from being solved.
Тип rawSql из постоянного:
rawSql :: (RawSql a, MonadIO m)
=> Text -- ^ SQL statement, possibly with placeholders.
-> [PersistValue] -- ^ Values to fill the placeholders.
-> ReaderT SqlBackend m [a]
runDB
вспомогательная функция, которая подключается к базе данных и возвращает IO [a]
, Исходя из определения rawSql, я ожидаю, что ограничение RawSql будет выполнено. Я не понимаю, почему возникает эта ошибка.
1 ответ
rawSql
универсально количественно. Это означает, что он не "извлекает RawSql
экземпляр из базы данных ", который будет то, что экзистенциальный тип SomeRawSql
выражает. Вместо этого он может извлекать значения из базы данных, если они имеют RawSql
экземпляр. Какой это тип выбирается вызывающим абонентом.
Вы также можете обернуть универсальное количественное определение в тип без параметров:
data SomeRawSql where
SomeRawSql :: (forall b. RawSql b => [b]) -> SomeRawSql
но я не думаю, что это было бы разумно, это просто пнуло бремя выбора типа в будущем. Параметричность - хорошая вещь, она позволяет вам фактически отслеживать, какие типы и куда идут. Не обходите это без реальной причины!
Совсем другой предмет - если вы хотите получить значение, тип которого вы на самом деле не знаете. Это не покрытоrawSql
, вам нужно реализовать это самостоятельно с помощью обертокDynamic
,