Учебник по Haskell - [39]

Шрифт
Интервал

базовые функции, получая остальные “на лету” применением двух-трёх операций, это выглядит

примерно как (2+3)*5, где вместо чисел стоят базовые функции, а операции + и * составляют

новые функции из простейших.

Такие обобщённые функции как id, const, (. ), map filter позволяют очень легко комбинировать различ-

ные функции. Бесточечный стиль записи функций превращает функции в простые значения или значения-

константы, которые можно подставлять в другие функции. В этом разделе мы немного потренируемся в пе-

регрузке численных значений и превратим числа в функции, функции и в самом деле станут константами.

Мы определим экземпляр Num для функций, которые возвращают числа. Смысл этих операций заключается в

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

падает по типу. Например для того чтобы умножить функции \t -> t+2 и \t -> t+3 мы составляем новую

функцию \t -> (t+2) * (t+3), которая получает на вход значение t применяет его к каждой из функций и

затем умножает результаты:

78 | Глава 5: Функции высшего порядка

module FunNat where

import Prelude(Show(.. ), Eq(.. ), Num(.. ), error)

instance Show (t -> a) where

show _ = error ”Sorry, no show. It’s just for Num”

instance Eq (t -> a) where

(==) _ _ = error ”Sorry, no Eq. It’s just for Num”

instance Num a => Num (t -> a) where

(+) = fun2 (+)

(*) = fun2 (*)

(-) = fun2 (-)

abs

= fun1 abs

signum

= fun1 signum

fromInteger = const . fromInteger

fun1 :: (a -> b) -> ((t -> a) -> (t -> b))

fun1 = (. )

fun2 :: (a -> b -> c) -> ((t -> a) -> (t -> b) -> (t -> c))

fun2 op a b = \t -> a t ‘op‘ b t

Функции fun1 и fun2 превращают функции, которые принимают значения, в функции, которые прини-

мают другие функции.

Из-за контекста класса Num нам пришлось объявить два фиктивных экземпляра для классов Show и Eq.

Загрузим модуль FunNat в интерпретатор и посмотрим что же у нас получилось:

Prelude> :l FunNat. hs

[1 of 1] Compiling FunNat

( FunNat. hs, interpreted )

Ok, modules loaded: FunNat.

*FunNat> 2 2

2

*FunNat> 2 5

2

*FunNat> (2 + (+1)) 0

3

*FunNat> ((+2) * (+3)) 1

12

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

значение к константе. Но на самом деле 2 это не константа, а значение 2 :: Num a => a и подспудно к двойке

применяется функция fromInteger. Поскольку в нашем модуле мы определили экземпляр Num для функций,

второе число 2 было конкретизировано по умолчанию до Integer, а первое число 2 было конкретизировано

до Integer -> Integer. Компилятор вывел из контекста, что под 2 мы понимаем функцию. Функция была

создана с помощью метода fromInteger. Эта функция принимает любое значение и возвращает двойку.

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

составлять и такие выражения:

*FunNat> let f = ((+) - (*))

*FunNat> f 1 2

1

Как была вычислена эта функция? Мы определили экземпляр функций для значений типа Num a => t

-> a. Если мы вспомним, что функция двух аргументов на самом деле является функцией одного аргумента:

Num a => t1 -> (t2 -> a), мы заметим, что тип Num a => (t2 -> a) принадлежит Num, теперь если мы

обозначим его за a’, то мы получим тип Num a’ => t1 -> a’, это совпадает с нашим исходным экземпляром.

Получается, что за счёт механизма частичного применения мы одним махом определили экземпляры Num

для функций любого числа аргументов, которые возвращают значение типа Num.

Итак функция f имеет вид:

\t1 t2 -> (t1 + t2) - (t1 * t2)

Подставим значения:

Функциональный калькулятор | 79

(\t1 t2 -> (t1 + t2) - (t1 * t2)) 1 2

(\t2 -> (1 + t2) - (1 * t2) 2

(1 + 2) - (1 * 2)

3 - 2

1

Теперь давайте составим несколько выражений с обобщёнными функциями. Для этого добавим в модуль

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

для списков и класс Ord:

module FunNat where

import Prelude(Show(.. ), Eq(.. ), Ord(.. ), Num(.. ), error)

import Data.Function(id, const, (. ), ($), flip, on)

import Prelude(map, foldr, filter, zip, zipWith)

...

и загрузим модуль в интерпретатор:

Prelude> :load FunNat

[1 of 1] Compiling FunNat

( FunNat. hs, interpreted )

Ok, modules loaded: FunNat.

Составим функцию, которая принимает один аргумент, умножает его на два, вычитает 10 и берёт модуль

числа.

*FunNat> let f = abs $ id * 2 - 10

*FunNat> f 2

6

*FunNat> f 10

10

Давайте посмотрим как была составлена эта функция:

abs $ id * 2 - 10

=>

abs $ (id * 2) - 10

-- приоритет умножения

=>

abs $ (\x -> x * \x -> 2) - 10

-- развернём id и 2

=>

abs $ (\x -> x * 2) - 10

-- по определению (*) для функций

=>

abs $ (\x -> x * 2) - \x -> 10

-- развернём 10

=>

abs $ \x -> (x * 2) - 10

-- по определению (-) для функций

=>

\x -> abs x . \x -> (x * 2) - 10

-- по определению abs для функций

=>

\x -> abs ((x * 2) - 10)

-- по определению (.)

=>

\x -> abs ((x * 2) - 10)

Функция возведения в квадрат:

*FunNat> let f = id * id

*FunNat> map f [1,2,3,4,5]

[1,4,9,16,25]

*FunNat> map (id * id - 1) [1,2,3,4,5]

[0,3,8,15,24]

Обратите внимание на краткость записи. В этом выражении (id * id - 1) проявляется основное пре-

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


Рекомендуем почитать
Уголовное право. Особенная часть

В книге кратко изложены ответы на основные вопросы темы «Уголовное право. Особенная часть». Издание поможет систематизировать знания, полученные на лекциях и семинарах, подготовиться к сдаче экзамена или зачета.Пособие адресовано студентам высших и средних образовательных учреждений, а также всем интересующимся данной тематикой.


Уголовно-исполнительное право

В книге кратко изложены ответы на основные вопросы темы «Уголовно-исполнительное право». Издание поможет систематизировать знания, полученные на лекциях и семинарах, подготовиться к сдаче экзамена или зачета.Пособие адресовано студентам высших и средних образовательных учреждений, а также всем интересующимся данной тематикой.


Самоучитель Adobe Premiere 6.5

Книга посвящена возможностям самого популярного средства цифрового видеомонтажа – Adobe Premiere 6.5. Описываются основные приемы работы с программой, приводятся сведения об управлении проектами и клипами, обсуждаются методы монтажа видео и звука, техника создания титров и добавления спецэффектов, а также освещается процесс окончательного монтирования фильма. На примерах рассматриваются все этапы создания и обработки фильмов для телевидения, видео и мультимедиа.Для широкого круга пользователей.


Финансовое право

В учебном пособии в краткой и доступной форме рассмотрены все основные вопросы, предусмотренные государственным образовательным стандартом и учебной программой по дисциплине «Финансовое право».Книга позволит быстро получить основные знания по предмету, а также качественно подготовиться к зачету и экзамену.Рекомендуется студентам, аспирантам и преподавателям по юридическим, экономическим и управленческим специальностям, а также сотрудникам банков.Автор книги, Шевчук Денис Александрович, имеет опыт преподавания различных дисциплин в ведущих ВУЗах Москвы (экономические, юридические, технические, гуманитарные), два высших образования (экономическое и юридическое), более 30 публикаций (статьи и книги), Член Союза Юристов Москвы, Член Союза Журналистов России, Член Союза Журналистов Москвы, Стипендиат Правительства РФ, опыт работы в банках, коммерческих и государственных структурах (в т.ч.


фгос  ответы

Содержащиеся в пособии контрольно-измерительные материалы (КИМы) для 5 класса, аналогичные материалам ЕГЭ, составлены в соответствии с программой общеобразовательных учреждений по русскому языку и учитывают возрастные особенности учащихся. В конце пособия даны ответы на все варианты тестов, предложены диктанты различных типов.Пособие адресовано учителям, ученикам, их родителям и всем, кому необходимо закрепить и систематизировать знания перед ЕГЭ.


Теория литературы. Чтение как творчество

Цель предлагаемого пособия – систематизировать и обогатить представления о природе, структуре и особенностях художественной литературы как вида искусства, помочь совершенствованию читательского мастерства. Книга снабжена кратким словарем основных литературоведческих понятий и терминов (составлен при участии доцента О.В. Быстровой).Для студентов филологических факультетов, учителей, преподавателей литературы высших и средних учебных заведений.