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

动态覆写类型类方法:如何用T类型自定义相等函数调用需Eq约束的预定义函数?

解决方案

核心思路是通过newtype包装原类型,为包装类型自定义Eq实例(使用T中携带的相等函数),这样就能直接调用需要Eq约束的预定义函数,无需重写。

以实现elemIndices'为例:

import Data.List (elemIndices)

data T a = T (a -> a -> Bool) [a]

elemIndices' :: a -> T a -> [Int]
elemIndices' x (T eq xs) = elemIndices (Wrap x) (map Wrap xs)
  where
    -- 局部定义包装类型
    newtype Wrap b = Wrap b
    -- 为包装类型实现Eq实例,复用传入的eq函数
    instance Eq (Wrap b) where
      Wrap a == Wrap b = eq a b

原理说明

  1. Wrap作为newtype是编译期语法糖,运行时不会带来额外开销,仅用于为原类型附加自定义Eq逻辑。
  2. 在where块中为Wrap b定义的Eq实例,会把==操作完全映射到传入的eq函数上——这样预定义的elemIndices会自动使用我们指定的相等规则,而非原类型的默认Eq实例。
  3. 把目标元素x和列表xs都包装成Wrap类型后调用elemIndices,由于列表长度、元素位置完全不变,返回的索引结果直接对应原列表。

测试验证

  • 传入elemIndices' 1 (T (==) [0,1,2,1,3]),结果为[1,3],和Data.List.elemIndices默认行为一致。
  • 传入elemIndices' 1 (T (/=) [0,1,2,1,3]),结果为[0,2,4],符合自定义相等逻辑的预期。

如果追求更高效率,可利用coerce替代map(newtype的零开销特性):

import Data.List (elemIndices)
import Data.Coerce (coerce)

data T a = T (a -> a -> Bool) [a]

elemIndices' :: a -> T a -> [Int]
elemIndices' x (T eq xs) = coerce (elemIndices (Wrap x) (coerce xs :: [Wrap a]))
  where
    newtype Wrap b = Wrap b
    instance Eq (Wrap b) where
      Wrap a == Wrap b = eq a b

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 01:58:06