52700.fb2 Учебник по Haskell - читать онлайн бесплатно полную версию книги . Страница 117

Учебник по Haskell - читать онлайн бесплатно полную версию книги . Страница 117

Этот набор значений мы будем называть окружением.

Обратите внимание на то, что в каждом составном конструкторе мы рекурсивно вызываем функцию eval,

мы словно обходим всё дерево выражения. Спускаемся вниз, до самых листьев в которых расположены либо

значения (Lit), либо переменные (Var). Нам было бы удобно иметь возможность пользоваться окружением

из любого узла дерева. В этом нам поможет тип Reader.

Представим что у нас есть значение типа Env и функция, которая позволяет читать значения переменных

по имени:

value :: Env -> String -> Int

Теперь определим функцию eval:

eval :: Exp -> Reader Env Int

eval (Lit n)

= pure n

eval (Neg n)

= liftA

negate $ eval n

eval (Add a b)

= liftA2 (+) (eval a) (eval b)

eval (Mul a b)

= liftA2 (*) (eval a) (eval b)

eval (Var name) = Reader $ \env -> value env name

Определение сильно изменилось, оно стало не таким наглядным. Теперь значение eval стало специаль-

ным, поэтому при рекурсивном вызове функции eval нам приходится поднимать в мир специальных функций

обычные функции вычитания, сложения и умножения. Мы можем записать это выражение

немного по другому:

eval :: Exp -> Reader Env Int

eval (Lit n)

= pure n

eval (Neg n)

= negateA $ eval n

eval (Add a b)

= eval a ‘addA‘ eval b

eval (Mul a b)

= eval a ‘mulA‘ eval b

eval (Var name) = Reader $ \env -> value env name

addA

= liftA2 (+)

mulA

= liftA2 (*)

negateA

= liftA negate

Тип Map

Для того чтобы закончить определение функции eval нам нужно определить тип Env и функцию value.

Для этого мы воспользуемся типом Map, он предназначен для хранения значений по ключу.

Этот тип живёт в стандартном модуле Data.Map. Посмотрим на его описание:

data Map k a = ..

Первый параметр типа k это ключ, а второй это значение. Мы можем создать значение типа Map из списка

пар ключ значение с помощью функции fromList.

Посмотрим на основные функции:

-- Создаём значения типа Map

-- создаём