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

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

instance Functor N where

fmap f x = case x of

Zero

-> Zero

Succ a

-> Succ (f a)

instance Functor (L a) where

fmap f x = case x of

Nil

-> Nil

Cons a b

-> Cons a (f b)

Это всё что нам нужно для того чтобы начать пользоваться функциями свёртки и развёртки! Определим

экземпляр Num для натуральных чисел:

instance Num Nat where

(+) a = fold $ \x -> case x of

Zero

-> a

Succ x

-> succ x

(*) a = fold $ \x -> case x of

242 | Глава 16: Категориальные типы

Zero

-> zero

Succ x

-> a + x

fromInteger = unfold $ \n -> case n of

0

-> Zero

n

-> Succ (n-1)

abs = undefined

signum = undefined

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

ла типа Integer определена через развёртку. Сравните с теми функциями, которые мы писали в главе про

структурную рекурсию. Теперь мы не передаём отдельно две функции, на которые мы будем заменять кон-

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

добавить ещё одно расширение TypeSynonymInstances наши рекурсивные типы являются синонимами, а не

новыми типами. В рамках стандарта Haskell мы можем определять экземпляры только для новых типов, для

того чтобы обойти это ограничение мы добавим ещё одно расширение.

*Fix> succ $ 1+2

(Succ (Succ (Succ (Succ (Zero)))))

*Fix> ((2 * 3) + 1) :: Nat

(Succ (Succ (Succ (Succ (Succ (Succ (Succ (Zero))))))))

*Fix> 2+2 == 2*(2::Nat)

True

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

кают голову и хвост списка:

headL :: List a -> a

headL x = case unFix x of