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

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

eval x = case x of

ValTrue

-> True

ValFalse

-> False

If p t e

-> if eval p then eval t else eval e

Val n

-> n

Add a b

-> eval a + eval b

Mul a b

-> eval a * eval b

Если eval получит логическое значение, то будет возвращено значение типа Bool, а на значение типа Exp

Int будет возвращено целое число. Давайте убедимся в этом:

Расширения | 255

*Prelude> :l Exp

[1 of 1] Compiling Exp

( Exp. hs, interpreted )

Ok, modules loaded: Exp.

*Exp> let notE x = If x ValFalse ValTrue

*Exp> let squareE x = Mul x x

*Exp>

*Exp> eval $ squareE $ If (notE ValTrue) (Val 1) (Val 2)

4

*Exp> eval $ notE ValTrue

False

*Exp> eval $ notE $ Add (Val 1) (Val 2)

< interactive>:1:14:

Couldn’t match expected type Bool’ against inferred type Int’

Expected type: Exp Bool

Actual type: Exp Int

In the return type of a call of Add’

In the second argument of ‘($)’, namely ‘Add (Val 1) (Val 2)’

Сначала мы определили две вспомогательные функции. Затем вычислили несколько значений. Haskell

очень часто применяется для построения компиляторов. Мы рассмотрели очень простой язык, но в более

сложном случае суть останется прежней. Дополнительный параметр позволяет нам закодировать в парамет-

ре тип функций нашего языка. Спрашивается: зачем нам дублировать вычисления в функции eval? Зачем нам

сначала кодировать выражение конструкторами, чтобы только потом получить то, что мы могли вычислить

и напрямую.

При таком подходе у нас есть полный контроль за деревом выражения, мы можем проводить дополни-

тельную оптимизацию выражений, если нам известны некоторые закономерности. Ещё функция eval может

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

Возможно этот язык гораздо мощнее Haskell по вычислительным способностям, но беднее в плане вырази-

тельности, гибкости синтаксиса. Тогда мы будем в функции eval проецировать разные конструкции Haskell

в конструкции другого языка. Такие программы называются предметно-ориентированными языками програм-

мирования (domain specific languages). Мы кодируем в типе Exp некоторую область и затем надстраиваем

над типом Exp разные полезные функции. На самом последнем этапе функция eval переводит всё дерево

выражения в значение или код другого языка.

Отметим, что не так давно было предложено другое решение этой задачи. Мы можем закодировать типы