52700.fb2
-- пустой Map
fromList :: Ord k => [(k, a)] -> Map k a
-- по списку (ключ, значение)
-- Узнаём значение по ключу
(! )
:: Ord k => Map k a -> k -> a
Отложенное вычисление выражений | 111
lookup
:: Ord k => k -> Map k a -> Maybe a
-- Добавляем элементы
insert :: Ord k => k -> a -> Map k a -> Map k a
-- Удаляем элементы
delete :: Ord k => k -> Map k a -> Map k a
Обратите внимание на ограничение Ord k в этих функциях, ключ должен быть экземпляром класса Ord.
Посмотрим как эти функции работают:
*Exp> :m +Data.Map
*Exp Data.Map> :m -Exp
Data.Map> let v = fromList [(1, ”Hello”), (2, ”Bye”)]
Data.Map> v ! 1
”Hello”
Data.Map> v ! 3
”*** Exception: Map.find: element not in the map
Data.Map> lookup 3 v
Nothing
Data.Map> let v1 = insert 3 ” Yo” v
Data.Map> v1 ! 3
” Yo”
Функция lookup является стабильным аналогом функции ! . В том смысле, что она определена с помощью
Maybe. Она не приведёт к падению программы, если для данного ключа не найдётся значение.
Теперь мы можем определить функцию value:
import qualified Data.Map as M(Map, lookup, fromList)
...
type Env = M.Map String Int
value :: Env -> String -> Int
value env name = maybe errorMsg $ M. lookup env name
where errorMsg = error $ ”value is undefined for ” ++ name
Обычно функции из модуля Data.Map включаются с директивой qualified, поскольку имена многих
функций из этого модуля совпадают с именами из модуля Prelude. Теперь все определения из модуля
Data.Map пишутся с приставкой M. .
Создадим вспомогательную функцию, которая упростит вычисление выражений:
runExp :: Exp -> [(String, Int)] -> Int
runExp a env = runReader (eval a) $ M. fromList env
Сохраним определение новых функций в модуле Exp. И посмотрим что у нас получилось:
*Exp> let env a b = [(”1”, a), (”2”, b)]
*Exp> let exp = 2 * (n 1 + n 2) - n 1
*Exp> runExp exp (env 1 2)
5
*Exp> runExp exp (env 10 5)
20