You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用GeneralizedNewTypeDeriving派生Vector和MVector实例?

修复Data.Vector.Unboxed中GeneralizedNewTypeDeriving派生实例的编译错误

问题背景

Data.Vector.Unboxed的Haddock文档提供了使用GeneralizedNewTypeDeriving自动派生Vector和MVector实例的示例,但添加必要编译指令后,代码在GHC 9.0.2(对应stack resolver lts-19.33)下无法通过类型检查,报错核心是coerce无法匹配m Int和m Foo的类型表示,原因是GHC无法确定monad参数m的角色。

原示例代码:

{-# LANGUAGE GeneralizedNewTypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeFamilies #-}

import qualified Data.Vector.Generic as G
import qualified Data.Vector.Generic.Mutable as M
import qualified Data.Vector.Unboxed as U

newtype Foo = Foo Int

newtype instance U.MVector s Foo = MV_Int (U.MVector s Int)
newtype instance U.Vector Foo = V_Int (U.Vector Int)
deriving instance M.MVector U.MVector Foo
deriving instance G.Vector U.Vector Foo
instance U.Unbox Foo

报错信息片段:

• Couldn't match representation of type: m Int
                           with that of: m Foo
    arising from a use of ‘GHC.Prim.coerce’
  NB: We cannot know what roles the parameters to ‘m’ have;
    we must assume that the role is nominal
• In the expression:
    GHC.Prim.coerce
      @(U.MVector (Control.Monad.Primitive.PrimState m) Int
        -> Int -> m Int)
      @(U.MVector (Control.Monad.Primitive.PrimState m) Foo
        -> Int -> m Foo)
      (M.basicUnsafeRead @U.MVector @Int)

用户已通过Data.Vector.Unboxed.Deriving的derivingUnbox实现需求,但希望使用GeneralizedNewTypeDeriving避免手动处理构造函数:

derivingUnbox
  "Foo"
  [t|Foo -> Int|]
  [|\(Foo i) -> i|]
  [|Foo|]

问题原因

GHC 9.0+对多参数类型类的角色推断更严格:

  • M.MVector和G.Vector属于多参数类型类,其元素类型参数默认被推断为nominal角色(即类型必须完全一致,不允许通过coerce跨类型转换)。
  • GeneralizedNewTypeDeriving依赖coerce来自动派生实例,但GHC无法确定monadm的参数角色,因此拒绝执行跨类型的coerce操作。

修复方案

添加RoleAnnotations语言扩展,显式标注U.MVector和U.Vector的元素类型参数为representational角色(允许基于底层表示的coerce转换),修改后的代码如下:

{-# LANGUAGE GeneralizedNewTypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE RoleAnnotations #-} -- 新增扩展

import qualified Data.Vector.Generic as G
import qualified Data.Vector.Generic.Mutable as M
import qualified Data.Vector.Unboxed as U

newtype Foo = Foo Int

-- 标注U.MVector的第二个参数(元素类型)为representational
type role U.MVector nominal representational
newtype instance U.MVector s Foo = MV_Int (U.MVector s Int)

-- 标注U.Vector的参数(元素类型)为representational
type role U.Vector representational
newtype instance U.Vector Foo = V_Int (U.Vector Int)

deriving instance M.MVector U.MVector Foo
deriving instance G.Vector U.Vector Foo
instance U.Unbox Foo

说明

  • RoleAnnotations允许我们手动指定类型构造器参数的角色,这里将元素类型参数设为representational,告诉GHC:只要两个类型的底层表示相同(比如Foo和Int作为newtype),就可以安全地通过coerce转换。
  • 此修复保留了GeneralizedNewTypeDeriving的便利性,无需手动编写构造函数的转换逻辑。

内容的提问来源于stack exchange,提问作者thisisrandy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 04:45:36