Вы не можете изменить Map
на месте (поскольку Haskell - чисто функциональный язык), но вы можете создать новый, который почти равен старой карте, за исключением нескольких измененных записей.
(Не беспокойтесь об эффективности: нелогично, новый Map
не требует полной копии старого.)
Например, предположим, что мы хотим посчитать частоты каждого символа в строке. Давайте напишем функцию, которая, учитывая char c
, увеличивает его количество, хранящееся в Map
import qualified Data.Map.Strict as M
countChar :: Char -> M.Map Char Int -> M.Map Char Int
countChar c oldMap = newMap
where
newMap = M.insertWith (+) c 1 oldMap
Переменная newMap
не нужна, она показана выше для ясности.
Функция insertWith
создает новую карту таким образом, чтобы при индексе c
она сохраняла 1, если на старой карте нет значения, или 1 + x
, если на старой карте есть предыдущее значение x
. .
Для обработки полной строки мы используем рекурсию:
countString :: String -> M.Map Char Int
countString "" = M.empty
countString (c:cs) = countChar c (countString cs)
Небольшой тест в GHCi:
> countString "here's an example"
fromList [(' ',2),('\'',1),('a',2),('e',4),('h',1),('l',1),('m',1)
,('n',1),('p',1),('r',1),('s',1),('x',1)]
Для более продвинутого решения, countString
также может быть переписано как сгиб, если требуется. Использование левого строгого сгиба также улучшило бы эффективность.
countString = foldl' (flip countChar) M.empty
Можно даже использовать государственную монаду, чтобы избежать обхода Map
. Если вы изучаете Haskell, не беспокойтесь об этом и начните с изучения способов решения таких задач с помощью рекурсии, сопоставления с образцом и нескольких библиотечных функций для Map
s.