haskell / haskell/containers

Imprecision about the identity of keys (when `Eq` is not the smallest reflexive relation)

未关闭
#587 4 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看
Map pitfall Set
主要语言
Haskell
星标
355
派生
194
平均合并
3 天 4 小时
30 天内合并 PR
4

描述

This issue is related to #290, #291, #52 (that one found by _github Related Issues_). There are situations where one would distinguish equal keys (in the sense of `Eq`) and identical keys (in the extreme pointer-identity).

The following is a (unrealistic) mock scenario, but it exemplifies the point. Here `Eq` on keys is very generous:
```haskell
import Data.Map (Map)
import qualified Data.Map as Map

newtype Key = Key { theKey :: Integer }
deriving (Show)

instance Eq Key where
_ == _ = True

instance Ord Key where
compare _ _ = EQ

test = show
$ Map.update (const $ Just "bar") (Key 2)
$ Map.singleton (Key 1) "foo"
```
What do we expect `test` to be? What does the documentation predict?
Lets read the documentation for `Map.update`!
https://github.com/haskell/containers/blob/f7273d15adcc9cac1b3853806cae9df056c9b9f3/Data/Map/Internal.hs#L1062
https://github.com/haskell/containers/blob/f7273d15adcc9cac1b3853806cae9df056c9b9f3/Data/Map/Internal.hs#L1053-L1055
According to the documentation "... is `(Just y)`, the key `k` is bound to the new value `y`", we expect the key `k = Key 2` to be bound to `"bar"`.
However, `test` is:
```haskell
fromList [(Key {theKey = 1},"bar")]
```
This means the documentation is imprecise (wrong is a hard word). The precise wording would be "...the existing key (which is `== k`) is bound to the new value `y`".

On a more general note, the API for containers prevents the user to conveniently and efficiently inspect and update the _keys_ of finite sets/maps. There seems to be a hidden assumption that no complex data structures are used as keys, and key equality is always uninteresting. This excludes practical scenarios where one would want to use finite maps also as managing data structure for the keys.

In case you wonder about _practical scenario_:
My own scenario is LALR parser generation where I maintain a map `m` from parse states (keys) to state numbers (values). A parse state is itself a map from parse items (dotted grammar rules) to lookaheads (token sets). LALR fuses parse states that only differ in the lookaheads, thus, for the sake of `m` I use an equality on parse states that ignores the lookaheads. (`Eq` is `(==) ``on`` keysSet`.) However, in the end I want the parse state with the largest lookaheads, thus, I need to update a key of `m` if I have a version of that key with larger lookaheads.

贡献指南

打开贡献指南

评估

这个 Issue 还没有评估数据。

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。