Использование ограничений в типизированном шаблоне Haskell

Я хотел бы использовать ограничения класса типов в своих фрагментах 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
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
8
0
195
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

К сожалению, это фундаментальный недостаток текущей реализации Typed Template Haskell, для которого нет простого обходного пути.

Ограничения просто не обрабатываются должным образом.

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

Другие вопросы по теме