import qualified Data.Map as M
-- созадние ассоциативного массива
m = M.fromList [("cat", 10), ("and", 100)]
M.lookup "cat" m -- возвращает Maybe от значения в массиве
M.lookup "dog" m
Just 10
Nothing
Эти ассоциативные массивы неизменяемые, т.е. нельзя, например, записать в Map другое значение по ключу. Можно только создать новый Map, в котором значение изменено:
:t M.adjust
m2 = M.adjust (+1) "cat" m
M.lookup "cat" m
M.lookup "cat" m2
Just 10
Just 11
Это класс типов, он содержит в себе те типы, которые как будто хранят внутри себя несколько других значений: список, кортеж, ассоциативный массив, MayBe, ...
https://hackage.haskell.org/package/base-4.15.0.0/docs/Data-Functor.html
-- List
fmap (+1) [10, 20, 30] -- эквиваленто map
-- MayBe
fmap (+1) (Just 10)
fmap (+1) Nothing
-- Кортежи, функция применяется только к последнему элементу
fmap (+1) (10, 20)
fmap (+1) (10, 20, 30)
fmap (+1) ("abc", 20)
-- Для Map
fmap (+1) m -- это ассоциативный массив про кота
[11,21,31]
Just 11
Nothing
(10,21)
(10,20,31)
("abc",21)
fromList [("and",101),("cat",11)]
Можно увидеть, что функторами являются функции: Functor ((->) r)
— это функции из типа r в какой-то другой. Функция хранит множество значений, для каждого аргумента своё значение. fmap для функции говорит, какую функцию применить к результату вычисления этой функции.
f :: Show a => a -> String
f x = show x ++ show x
f 42
f "abc"
f2 = fmap (\x -> x ++ "!") f
f2 42
"4242"
"\"abc\"\"abc\""
"4242!"
Можно сделать функтором наши собственные структуры. Например, дерево. fmap будет заменять по указанному правилу каждое значение в дереве.
При реализации функтора важно, чтобы
(fmap g (fmap f X)) = fmap (g.f) X
fmap (*2) (fmap (+1) [10, 20, 30])
fmap ((*2) . (+1)) [10, 20, 30]
[22,42,62]
[22,42,62]