在类型化模板 Haskell 中使用约束

如何解决在类型化模板 Haskell 中使用约束

我想在我的类型化模板 Haskell 片段中使用类型类约束,但无法让它们工作:实例似乎在拼接中丢失了。

这是我的代码一个独立的最小化版本,用于演示该问题。第一个模块定义了一个类型化模板 Haskell 宏 memoryMap,它不对 tagram0 施加任何约束,它通过 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

解决方法

不幸的是,这是当前类型化模板 Haskell 实现的一个基本缺陷,没有简单的解决方法可用。

只是没有正确处理约束。

在研究如何实现 generics-sop 的分阶段版本时,我们遇到了同样的问题。您可能想看看 Mongoose Middleware 论文的第 5 部分。我们也有一个在 Template Haskell 中处理约束的解决方案,但是这个解决方案需要在 GHC 中实现,并且目前仅在一个实验分支中可用(有关如何尝试的一些说明,请参阅 Staged Sums of Products) .目前,该分支处于不确定状态,因为由于所有线性类型的变化,它需要显着的 rebase。希望我们能在不久的将来开始这样做,因为我真的很想在类型化模板 Haskell 中进行适当的约束处理。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?