【问题标题】:Custom equality semantics for Immutable.js data structuresImmutable.js 数据结构的自定义相等语义
【发布时间】:2017-01-26 05:00:52
【问题描述】:

我希望Sanctuary 提供Fantasy Land - 兼容的 Map 和 Set 类型以及基于值的相等语义。理想情况下,这些值是不可变的,尽管这并不重要,因为 Sanctuary 会提供纯函数来合并和以其他方式操作这些值。

我很想利用Immutable.js 团队所做的出色工作;我想实现持久数据结构需要付出相当大的努力!

Immutable.js 提供的 API 并不重要,因为 Sanctuary 会公开与这些值交互的函数。但是,这些类型的相等语义至关重要。

这对我的用例来说是不可接受的:

> Map([[[1, 2, 3], 'foo'], [[1, 2, 3], 'bar']])
Map { [1,2,3]: "foo", [1,2,3]: "bar" }

[1, 2, 3][1, 2, 3] 的值相同。应该不可能有两个具有相同键的映射条目。

-0的处理也有问题:

> Immutable.is(Map([[0, 0]]), Map([[-0, -0]]))
true

我意识到可以通过定义 equals 方法来定义自己类型的相等语义,但我希望重新定义原生类型(例如 Array 和 Number)的相等语义。 这可能吗?相关文件似乎是is.js,但我没有看到自定义挂钩。

Sanctuary 的 Map 类型可能会包装 Immutable.js 的 Map 类型。这将提供:

  • 一种处理-0的方法;
  • 在执行assoc 操作之前执行基于值的相等检查的机会,这通常会导致重复键;和
  • 一个定义各种fantasy-land/ 方法的地方。

也许:

Map k v = { negativeZero :: Maybe v
          , value :: ImmutableMap k v
          , fantasy-land/equals :: Map k v ~> Map k v -> Boolean
          , fantasy-land/map :: Map k v ~> (k -> a) -> Map a v
          , fantasy-land/bimap :: Map k v ~> (k -> a, v -> b) -> Map a b
          , ...
          }

我想确保在创建上述包装器之前没有其他方法可以实现所需的相等语义。 facebook/immutable-js#519 没有希望。

【问题讨论】:

  • 以下仅代表个人观点。我没有引入新的抽象数据类型,而是通过定义一个单独的函数/构造函数以编程方式解决这个问题,该函数/构造函数在添加条目/构造Map 时负责值相等检查。我总是倾向于接受 JS 的局限性。此外,我怀疑在Maps 中用作键的对象是否真的受益于持久数据结构,因为它们应该很小,就像值对象一样。 Immutable.js 似乎更适合像 redux 存储这样的大型数据结构。
  • 感谢您的反馈,@ftor。您说用作键的对象不会从持久性数据结构中受益,但是数据结构本身(而不是其键)是否会从持久性中受益,这不是相关的问题吗?由于包装似乎是必要的,我现在想知道我们是否应该包装原生 Map 类型并避免依赖:sanctuary-js/sanctuary#233.
  • 也许尝试在ArrayNumber 周围使用类似新类型的包装器?修改内置函数如此重要的属性可能是毁灭性的。
  • 糟糕,我误解了“重新定义原生类型(如数组和数字)的相等语义”。很好,您不想进行全局修改 :-) 听起来定义 Array.prototype.equalsNumber.prototype.equals 可以解决问题。
  • 我的意思是你应该在ArrayNumber 周围使用一个新类型的包装器,它定义了你的自定义.equals 方法,然后为所有数组和数字隐式实例化包装器传递到你包装好的Map

标签: javascript functional-programming immutable.js sanctuary


【解决方案1】:

虽然很久以前有人问过这个问题,但我没有看到对这个简单解决方案的引用:

const {Map, fromJS} = Immutable

// instead of this:
console.log(
  Map([[[1, 2, 3], 'foo'], [[1, 2, 3], 'bar']]).toString(),
)

// do this:
console.log(
  Map(fromJS([[[1, 2, 3], 'foo'], [[1, 2, 3], 'bar']])).toString()
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/4.0.0-rc.12/immutable.min.js"></script>

通过使用fromJS 深度转换对象,您可以获得值相等

【讨论】:

猜你喜欢
  • 2013-08-30
  • 1970-01-01
  • 1970-01-01
  • 2015-12-18
  • 1970-01-01
  • 2022-11-24
  • 2021-02-22
  • 2012-09-25
  • 1970-01-01
相关资源
最近更新 更多