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

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

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

падает по типу. Например для того чтобы умножить функции \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