I have a record in a document that use two IntMaps:
data Doc = Doc { kernels :: IntMap Kernel, nodes :: IntMap Node }
But I found that the keys from both IntMaps have different meaning and I fail to separate in two differents types and don't get errors when mix kernel types and node types. I want to have functions that check the the keys from kernel map and node maps and don't allow mix-up. E.g:
someFunction :: Doc -> KernelKey -> NodeKey -> a
someFunction doc k1 k2 = .....
Instead of current:
someFunction :: Doc -> Int -> Int -> a
someFunction doc k1 k2 = .... -- warning check twice k1 and k2
Is it posible? Or I shall change from IntMap
to Map
.
Thanks
You can use newtype
to make wrappers around Int
to distinguish their meaning.
newtype KernelKey = KernelKey Int
newtype NodeKey = NodeKey Int
someFunction :: Doc -> KernelKey -> NodeKey -> a
someFunction doc (KernelKey k1) (NodeKey k2) = ...
That way, you can still use IntMap
internally, but expose a more type-safe interface, especially if you also control how the KernelKey
and NodeKey
values get created, i.e. you don't export their constructors so users only get them as return values from your other functions.
Note that newtype
wrappers disappear at run time, so this extra wrapping and unwrapping does not affect performance in any way.
You could create a unified key type and wrap the IntMap API for your Doc type. It might look something like this.
data DocValue = DocKernel Kernel
| DocNode Node
data DocKey = KernelKey Int
| NodeKey Int
docLookup :: DocKey -> Doc -> Maybe DocValue
The nice thing about that solution is that you only need one copy of each of the map API functions that you need. Here's a different solution which is closer to the code you have.
newtype NodeKey = NodeKey Int
newtype KernelKey = KernelKey Int
lookupDocNode :: NodeKey -> Doc -> Maybe Node
lookupDocKernel :: KernelKey -> Doc -> Maybe Kernel
You could also do this solution without the newtypes. Both these solutions give you type safety. In the first one you have to specify what you want with types. In the second one you specify it by choosing which function to call.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With