Я хотел бы использовать ограничения класса типов в своих фрагментах Typed Template Haskell, но просто не могу заставить их работать: кажется, что экземпляры отсутствуют внутри соединения.
Вот автономная минимизированная версия моего кода для демонстрации проблемы. Первый модуль определяет макрос Typed Template Haskell memoryMap, который не накладывает никаких ограничений на tag, и ram0, который накладывает ограничения tag на C:
{-# LANGUAGE TemplateHaskell, QuasiQuotes #-}
{-# LANGUAGE DerivingStrategies, GeneralizedNewtypeDeriving #-}
module RetroClash.MemoryTH where
import Control.Monad.Identity
import Language.Haskell.TH
class C a where
newtype Signal tag a = Signal{ runSignal :: a }
newtype Addressing dom a = Addressing
{ runAddressing :: Identity a
}
deriving newtype (Functor, Applicative, Monad)
memoryMap :: Addressing tag () -> TExpQ (Signal tag (Maybe dat) -> Signal tag (Maybe dat))
memoryMap addressing = [|| \ wr -> wr ||]
ram0 :: (C tag) => Addressing tag ()
ram0 = pure ()
Затем я пытаюсь использовать его напрямую из другого модуля:
{-# LANGUAGE TemplateHaskell #-}
module RetroClash.MemoryTHTest where
import RetroClash.MemoryTH
foo
:: (C tag)
=> Signal tag (Maybe Int)
-> Signal tag (Maybe Int)
foo = $$(memoryMap ram0)
Однако это приводит к следующей ошибке типа из GHC 8.10:
src/RetroClash/MemoryTHTest.hs:11:20: error:
• No instance for (C tag) arising from a use of ‘ram0’
• In the first argument of ‘memoryMap’, namely ‘ram0’
In the expression: memoryMap ram0
In the Template Haskell splice $$(memoryMap ram0)
|
11 | foo = $$(memoryMap ram0)
| ^^^^
Одна вещь, которую я пробовал просто так, это добавить ограничение C непосредственно к возвращаемому типу макроса:
memoryMap :: Addressing tag () -> TExpQ (C tag => Signal tag (Maybe dat) -> Signal tag (Maybe dat))
memoryMap addressing = [|| \ wr -> wr ||]
Даже если бы это сработало, это не решило бы мою первоначальную проблему, потому что ограничения должны исходить в открытом мире из того, что происходит в аргументе Addressing tag (); но в любом случае эта версия терпит неудачу, потому что она сталкивается с ограничениями непредикативности GHC:
• Illegal qualified type:
C tag => Signal tag (Maybe dat) -> Signal tag (Maybe dat)
GHC doesn't yet support impredicative polymorphism





К сожалению, это фундаментальный недостаток текущей реализации Typed Template Haskell, для которого нет простого обходного пути.
Ограничения просто не обрабатываются должным образом.
Мы столкнулись с той же проблемой, пытаясь реализовать поэтапную версию generics-sop. Возможно, вы захотите взглянуть на Раздел 5 статьи Поэтапные суммы произведений. У нас также есть решение для обработки ограничений в Template Haskell, но это решение нуждается в реализации в GHC, и на данный момент оно доступно только в экспериментальной ветке (см. попробуй это). На данный момент ветка находится в подвешенном состоянии, т.к. нуждается в значительном ребейзинге из-за всех изменений линейных типов. Будем надеяться, что в какой-то момент мы скоро займемся этим, потому что мне бы очень хотелось иметь правильную обработку ограничений в Typed Template Haskell.