52700.fb2
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