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

如何实现深度嵌套函数调用多态,新增类型无需修改isEqual主逻辑

方案1:注册式类型分发(优先推荐,纯函数+无方法结构体,对齐Haskell Eq类型类思路)

Haskell中通过Eq类型类为不同类型独立定义相等性实现,新增类型只需新增实例不需要修改原有逻辑,我们可以用全局注册表模拟这个模式,完全不侵入结构体定义:

// 相等实现注册表,key为类型标识,value为对应类型的相等判断函数
const eqImplRegistry = new Map()

// 新增类型时仅需调用该方法注册相等实现,不需要修改isEqual主逻辑
function registerEqImpl(typeTag, eqFn) {
  eqImplRegistry.set(typeTag, eqFn)
}

// 主isEqual逻辑,永久不需要修改
function isEqual(a, b) {
  const typeA = getTypeTag(a)
  const typeB = getTypeTag(b)
  // 类型不同直接返回不等
  if (typeA !== typeB) return false
  const eqImpl = eqImplRegistry.get(typeA)
  if (!eqImpl) throw new Error(`未实现${typeA}类型的自定义相等判断`)
  // 传入isEqual本身用于嵌套类型的递归判断
  return eqImpl(a, b, isEqual)
}

// 自定义结构体仅需加类型标识字段,无任何方法
const Set = (items) => ({
  _type: 'Set',
  items: items
})

// 独立注册Set类型的相等实现
registerEqImpl('Set', (setA, setB, recursiveEq) => {
  if (setA.items.length !== setB.items.length) return false
  for (let i = 0; i < setA.items.length; i++) {
    if (!recursiveEq(setA.items[i], setB.items[i])) return false
  }
  return true
})

// getTypeTag可根据你的语言类型系统实现,比如优先取结构体的_type字段,基础类型返回对应标识
function getTypeTag(val) {
  if (val && typeof val === 'object' && '_type' in val) return val._type
  // 基础类型自定义标签,不需要依赖原生==判断
  if (typeof val === 'number') return 'Number'
  if (typeof val === 'string') return 'String'
  return typeof val
}

// 基础类型的相等逻辑也可以自定义注册,比如实现浮点数精度判断
registerEqImpl('Number', (a, b) => Math.abs(a - b) < 1e-9)

该方案完全满足纯函数+无方法结构体的要求,新增类型只需要单独写对应相等实现并注册即可,不需要改动任何现有逻辑。

方案2:显式传递相等函数(无全局状态,纯函数式)

如果不想引入全局注册表,可以将相等函数作为参数透传,适合多场景下需要不同相等语义的情况:

// 工具函数新增eq参数
function isIntersection(setTest, setA, setB, eq) {
  let i = 0
  while (i < setTest.length) {
    const t = setTest[i]
    if (includes(setA, t, eq) || includes(setB, t, eq)) {
      i++
    } else {
      return false
    }
  }
  return true
}

function includes(set, element, eq) {
  for (const x of set) {
    if (eq(element, x)) return true
  }
  return false
}

// 使用时传入组装好的相等函数即可
const customEq = combineEqImpls([setEq, numberEq, stringEq])
isIntersection(testSet, a, b, customEq)

方案3:必须使用类的实现方案

如果必须用类,可以采用静态方法分发的方式,不需要在实例上挂载方法:

class Set {
  constructor(items) {
    this.items = items
  }
  // 静态相等实现,不是实例方法
  static isEqual(a, b, recursiveEq) {
    if (a.items.length !== b.items.length) return false
    for (let i = 0; i < a.items.length; i++) {
      if (!recursiveEq(a.items[i], b.items[i])) return false
    }
    return true
  }
}

// 主isEqual逻辑不需要修改
function isEqual(a, b) {
  if (a.constructor !== b.constructor) return false
  if (typeof a.constructor.isEqual === 'function') {
    return a.constructor.isEqual(a, b, isEqual)
  }
  // 基础类型自定义判断逻辑
  return customPrimitiveEq(a, b)
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.18 02:27:02