You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

能否为关联类型族设置默认类型值?结合代码场景寻求实现方案

给关联类型族设置默认类型与对应方法的默认实现

当然可以!你想要的给关联类型族指定默认类型,同时为对应的方法提供基于该默认类型的实现,在GHC Haskell里是完全可行的。我们只需要调整类的定义,结合几个必要的语言扩展就能实现你的需求。

完整实现代码

{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeFamilyDependencies #-}
{-# LANGUAGE DefaultSignatures #-}
module Study where

class C' a where
  -- 定义带依赖的关联类型族,并指定默认类型为 [a]
  type T' a = r | r -> a
  type T' a = [a]

  -- 定义方法,并为默认类型提供专属的默认实现
  pred' :: T' a -> Bool
  default pred' :: (T' a ~ [a]) => T' a -> Bool
  pred' = not . null

代码解释

  1. 关联类型的默认值
    C'类中,我们先声明了带依赖的关联类型T' a,紧接着添加type T' a = [a]——这是GHC支持的语法,用于给关联类型族指定默认的实例类型。当某个实例没有自定义T' a时,就会自动使用这个默认的[a]类型。

  2. 方法的条件默认实现
    对于pred'方法,我们使用default关键字给它添加了一个带约束的默认实现:(T' a ~ [a])确保只有当T' a等于默认的[a]时,才会启用这个not . null的实现。如果某个实例自定义了T' a,那么这个默认实现就会失效,编译器会要求你为该实例手动实现pred',避免类型不匹配的错误。

使用示例

示例1:使用默认类型与默认实现

当我们声明一个不自定义T'pred'的实例时,会自动继承默认的设置:

instance C' Int

测试一下:

-- 输出 True,因为 [1,2,3] 非空
pred' ([1,2,3] :: [Int])

-- 输出 False,因为空列表
pred' ([] :: [Int])

示例2:自定义关联类型与方法

如果我们需要为某个类型指定不同的T',就必须手动实现pred'(或者也可以复用逻辑,只要类型匹配):

instance C' Bool where
  type T' Bool = String
  pred' = not . null -- 这里复用了相同的逻辑,也可以写自定义实现

测试:

-- 输出 True
pred' ("hello" :: String)

-- 输出 False
pred' ("" :: String)

注意事项

  • 必须启用DefaultSignatures扩展,因为我们使用了带约束的默认方法实现。
  • 你的类型族依赖r -> a依然有效:默认类型[a]满足“给定r可以唯一确定a”的要求,所以不会违反依赖规则。
  • 如果某个实例只自定义T'但不实现pred',编译器会抛出错误,提示你必须提供pred'的实现——这是合理的,因为默认实现只适用于[a]类型。

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

火山引擎 最新活动