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

如何为带Typeable约束的自定义GADT实现外部库Arrow类型类实例

为带Typeable约束的自定义Arrow类型实现标准Arrow实例的方案

核心矛盾在于标准Arrow类的arr方法签名要求支持任意无约束的a/b类型,而你的GADT构造要求a/b必须携带Typeable约束。针对Typeable这个特定约束,有完全兼容标准Arrow接口的安全实现方案;如果是其他非全量覆盖的约束,也有可落地的折中方案。


方案1:利用Typeable全类型覆盖特性实现安全实例

从GHC 7.8版本开始,所有属于Type种类的类型都会自动生成Typeable实例,不存在例外情况。因此我们可以安全地构造Typeable约束的证明,不需要依赖外部传入:

{-# LANGUAGE GADTs #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE TypeApplications #-}

import Control.Arrow (Arrow(..))
import Data.Typeable (Typeable)
import Data.Constraint (Dict(..))
import Unsafe.Coerce (unsafeCoerce)

data MyArr a b where
  Arr :: (Typeable a, Typeable b) => (a -> b) -> MyArr a b

-- 安全构造Typeable约束证明:所有Type种类的类型都有Typeable实例
typeableDict :: forall a. Dict (Typeable a)
typeableDict = unsafeCoerce (Dict :: Dict ())

instance Arrow MyArr where
  arr f = case (typeableDict @a, typeableDict @b) of
    (Dict, Dict) -> Arr f
  -- 其余Arrow方法可按照普通GADT模式匹配实现
  (Arr f) >>> (Arr g) = Arr (g . f)
  first (Arr f) = Arr \(a, c) -> (f a, c)

方案优势:

  • 完全兼容标准Arrow接口,可直接使用proc notation和所有第三方Arrow生态库
  • 约束检查完全在编译期完成,无运行时开销
  • 用到的unsafeCoerce是100%安全的,不会触发任何运行时错误

方案2:通用约束场景的折中实现

如果你未来需要替换为非全量覆盖的约束(比如自定义的类,只有部分类型有实例),无法保证所有a/b都满足约束,可以选择两种折中路径:

  1. 延迟约束检查到运行时:在arr方法中通过Data.Typeable或约束反射库检查约束是否满足,不满足则抛出明确的运行时错误,这种方案依然可以兼容标准Arrow接口,只需要在文档中明确说明支持的类型范围即可。
  2. 自定义Arrow类+语法扩展:如果完全不能接受运行时错误,可以使用你提到的带关联约束类的自定义Arrow定义,配合arrows等QuasiQuoter工具,替换Haskell原生proc notation的arr调用,实现编译期约束检查。

内容的提问来源于stack exchange,提问作者Josh.F

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 18:24:04