【问题标题】:Illegal polymorphic or qualified type using RankNTypes and TypeFamilies使用 RankNTypes 和 TypeFamilies 的非法多态或限定类型
【发布时间】:2012-12-13 12:21:43
【问题描述】:

我一直在慢慢地移植llvm 包以使用数据类型、类型族和类型nats,并在尝试删除用于分类值的两种新类型(ConstValue 和@ 987654324@) 通过引入一个新的Value 类型,该类型由其常量参数化。

CallArgs 只接受Value 'Variable a 参数,并提供将Value 'Const a 转换为Value 'Variable a 的函数。我想概括CallArgs 以允许每个参数为'Const'Variable。这是否可以使用类型族以某种方式对其进行编码?我认为这可能对fundeps是可行的。

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeFamilies #-}

data Const = Const | Variable

data Value (c :: Const) (a :: *)

type family CallArgs a :: * 
type instance CallArgs (a -> b) = forall (c :: Const) . Value c a -> CallArgs b
type instance CallArgs (IO a)   = IO (Value 'Variable a)

...编译失败:

/tmp/blah.hs:10:1: 非法多态或限定类型: forall (c :: Const)。值 c a 在“CallArgs”的类型实例声明中

以下解决方案适用的地方(相当于遗留代码),但需要用户强制转换每个常量Value

type family CallArgs' a :: * 
type instance CallArgs' (a -> b) = Value 'Variable a -> CallArgs' b
type instance CallArgs' (IO a)   = IO (Value 'Variable a)

【问题讨论】:

  • 评论随机路人:上述非法多态类型错误记录在haskell.org/ghc/docs/latest/html/users_guide/…
  • 我不确定,但forall 的优先级是否使得(forall (c :: Const) . Value c a) -> CallArgs bforall (c :: Const) . Value c a -> CallArgs 不同? (即更紧密地将forall 分组。)
  • @dbaupp: forall 是一个变量绑定结构,类似于 lambda,并且具有基本相同的“优先级”——它的范围在语法上尽可能向右延伸。
  • @dbaupp 我更新了这个问题。我认为这不会从根本上改变问题,因为这两种情况都不受支持。
  • @NathanHowell 哦,那个编辑非常令人惊讶!您是否希望 CallArgs (a -> b) 表示一个可以接受 Value 'Const aValue 'Variable a 作为其第一个参数的函数(由调用该函数的人自行决定)还是表示一个接受作为其第一个参数的函数可以是Value 'Const aValue 'Variable a 的值(由函数本身决定)?如果是后者,我的答案可能需要更新一下。

标签: haskell type-families


【解决方案1】:

您要求的CallArgs 有点像一个非确定性函数,它接受a -> b 并返回Value 'Const a -> blahValue 'Variable a -> blah。有时您可以使用非确定性函数做的一件事是翻转它们。事实上,这个有一个确定性逆。

type family   UnCallArgs a
type instance UnCallArgs (Value c a -> b) = a -> UnCallArgs b
type instance UnCallArgs (IO 'Variable a) = IO a

现在,任何你会写这样的类型的地方

foo :: CallArgs t -> LLVM t

或者类似的东西,你可以这样写:

foo :: t -> LLVM (UnCallArgs t)

当然,您可能想选择一个比 UnCallArgsNative 或类似名称更好的名称,但要做到这一点需要一些我没有的领域知识。

【讨论】:

  • 我仍然想知道它是类型族的基本功能,还是不是 GHC 中实现的功能?从查看 TcMType.lhs:checkValidFamInst 来看,将 forall 移动到有意义的位置仍然无法进行类型检查,这似乎是明确的。
  • 那是如何不确定的?它不返回两种类型中的任何一种,它返回包含量词的单一类型,与返回另一个函数的值的函数没有真正的不同。 GHC 的类型级语言并不是真正的高阶语言,量词在这里也不是一流的实体是另一回事。
  • @C.A.McCann 抱歉,我无意暗示不存在确定性函数,只是您可以将该函数视为非确定性函数。我稍微调整一下。
  • @NathanHowell 至于这是基本还是未实现,我真的不知道。
  • 类型实例的右侧不允许使用 Forall,它是类型系统的基本属性。不幸的是,无法快速找到参考资料...
【解决方案2】:

将包装 forall c。在newtype AV 为您工作?

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeFamilies #-}

data CV = Const | Variable

data Value (c :: CV) (a :: *)

data AV a = AV (forall c. Value c a)

type family CallArgs a :: * 
type instance CallArgs (a -> b) = AV a -> CallArgs b
type instance CallArgs (IO a)   = IO (Value 'Variable a)

【讨论】:

  • 这真的和今天没有什么不同。我想让它对任何一种类型的值进行操作。
  • forall (c :: Const) . (Value c a -> CallArgs b) 似乎与 (forall (c :: Const) . Value c a) -> CallArgs b 不同
  • 是的,它们是不同的。但是已经存在来自Value 'Const a -> Value 'Variable a 的转换功能,这就是它今天的工作方式。我没有看到在使用 API 时将所有值或只是一个子集装箱/转换为不同,这两种情况都是不可取的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-18
  • 1970-01-01
  • 2019-02-09
相关资源
最近更新 更多