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

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

deriving (Show, Eq)

У нас есть тип Exp, который может быть либо переменной Var с данным строчным именем, либо целочис-

ленной константой Lit, либо одной из трёх операций: вычитанием (Neg), сложением (Add) или умножением

(Mul).

Такие типы называют абстрактными синтаксическими деревьями (abstract syntax tree, AST). Они содержат

описание выражений. Теперь вместо того чтобы сразу проводить вычисления мы будем собирать выражения

в значении типа Exp. Сделаем экземпляр для Num:

instance Num Exp where

negate

= Neg

(+)

= Add

(*)

= Mul

fromInteger = Lit . fromInteger

abs

= undefined

signum

= undefined

Также определим вспомогательные функции для обозначения переменных:

var :: String -> Exp

var = Var

n :: Int -> Exp

n = var . show

Функция var составляет переменную с данным именем, а функция n составляет переменную, у которой

имя является целым числом. Сохраним эти определения в модуле Exp. Теперь у нас всё готово для составле-

ния выражений:

*Exp> n 1

Var ”1”

*Exp> n 1 + 2

Add (Var ”1”) (Lit 2)

*Exp> 3 * (n 1 + 2)

Mul (Lit 3) (Add (Var ”1”) (Lit 2))

*Exp> - n 2 * 3 * (n 1 + 2)

Neg (Mul (Mul (Var ”2”) (Lit 3)) (Add (Var ”1”) (Lit 2)))

110 | Глава 7: Функторы и монады: примеры

Теперь давайте создадим функцию для вычисления таких выражений. Она будет принимать выражение

и возвращать целое число.

eval :: Exp -> Int

eval (Lit n)

= n

eval (Neg n)

= negate $ eval n

eval (Add a b)

= eval a + eval b

eval (Mul a b)

= eval a * eval b

eval (Var name) = ???

Как быть с конструктором Var? Нам нужно откуда-то узнать какое значение связано с переменной. Функ-

ция eval должна также принимать набор значений для всех переменных, которые используются в выражении.