I'm working on a project that references unordered-containers-0.2.8.0:Data.HashMap.Base.HashMap
.
The module containing value of that type does not state where it came from in import sections and I cannot import Data.HashMap.Base
.
However :bro
wsing suggests that the type is intended to be abstract at least in some cases.
> :bro Data.HashMap.Lazy
[...]
unordered-containers-0.2.8.0:Data.HashMap.Base.toList ::
unordered-containers-0.2.8.0:Data.HashMap.Base.HashMap k v
-> [(k, v)]
Does it mean I can import functions from either Lazy
or Strict
variants?
Yes, in the unordered-containers
package, the intention is that you either import Data.HashMap.Lazy
or Data.HashMap.Strict
. Both variants have strict keys (evaluated to WHNF) and differ in whether values are also evaluated to WHNF or not.
In the source package for unordered-containers
, there is a hidden module Data.HashMap.Base
that contains code shared by both the lazy and strict variants. Because this module is hidden (technically, because it is listed in the package's Cabal file under the other-modules
stanza instead of the exposed-modules
stanza), it is not intended to be imported directly, but only indirectly via one of the other two modules.
For toList
in particular, the exposed modules Data.HashMap.Lazy
and Data.HashMap.Strict
both use (i.e., re-export) the same definition of toList
defined in the hidden module Data.HashMap.Base
, which is why you're seeing this in your GHCI browsing.
If you import one of the modules in GHCI, then you should be able to inspect toList
and its component types:
> import Data.HashMap.Strict
> :t toList
toList :: HashMap k v -> [(k, v)]
> :i HashMap
type role HashMap nominal representational
data HashMap k v
= unordered-containers-0.2.7.2:Data.HashMap.Base.Empty
...
In fact, you'll discover that the same HashMap
definition is used for both strict and lazy variants, so it's not an "abstract" type in the sense you're thinking: both implementations use the same underlying concrete data structure and differ in how the functions operating on that data structure use it.
This is true for the Data.Map.Strict
and Data.Map.Lazy
plain maps, too, by the way. A "strict" map can be used with lazy operations and vice versa, because "strict" and "lazy" maps are the same object. Quoting from the documentation for Data.Map.Lazy
:
API of this module is strict in the keys, but lazy in the values. If you need value-strict maps, use Data.Map.Strict instead. The Map type itself is shared between the lazy and strict modules, meaning that the same Map value can be passed to functions in both modules (although that is rarely needed).