@@ -2154,7 +2154,7 @@ disjoint (Bin _ k _ l r) t
2154
2154
-- the other, by using the values of the former as keys for lookups
2155
2155
-- in the latter.
2156
2156
--
2157
- -- Complexity: \( O (n * \log(m) ) \), where \(m\) is the size of the first argument
2157
+ -- Complexity: \( O (n \log m ) \), where \(m\) is the size of the first argument
2158
2158
--
2159
2159
-- > compose (fromList [('a', "A"), ('b', "B")]) (fromList [(1,'a'),(2,'b'),(3,'z')]) = fromList [(1,"A"),(2,"B")]
2160
2160
--
@@ -2166,6 +2166,22 @@ disjoint (Bin _ k _ l r) t
2166
2166
-- 'compose' that forced the values of the output 'Map'. This version does not
2167
2167
-- force these values.
2168
2168
--
2169
+ -- ==== __Note on complexity__
2170
+ --
2171
+ -- This function is asymptotically optimal. Given @n :: Map a b, m :: Map b c@,
2172
+ -- the composition essentially maps each @a@ in @n@ to @Maybe c@, since the
2173
+ -- composed lookup yields either one of the @c@ in @m@ or @Nothing@. The number
2174
+ -- of possible such mappings is \((|m| + 1) ^ {|n|}\).
2175
+ -- We now follow a similar reasoning to the one for
2176
+ -- [sorting](https://en.wikipedia.org/wiki/Comparison_sort#Number_of_comparisons_required_to_sort_a_list).
2177
+ -- To distinguish between \(x\) possible values, we need
2178
+ -- \( \lceil \log_2 x \rceil \) bits. Thus, we have a lower bound of
2179
+ -- \(\log_2 \left((|m| + 1) ^{|n|} \right) = |n| \cdot \log_2 (|m| + 1)\) bits.
2180
+ -- @Map@ lookups are comparison-based, and each comparison gives us at most
2181
+ -- one bit of information: in the worst case we'll always be left with at least
2182
+ -- half of the remaining possible values, meaning we need at least as many
2183
+ -- comparisons as we need bits.
2184
+ --
2169
2185
-- @since 0.6.3.1
2170
2186
compose :: Ord b => Map b c -> Map a b -> Map a c
2171
2187
compose bc ! ab
0 commit comments