Jest to często przydatne, zwłaszcza dla rekurencyjnych typów danych z wielu konstruktorów , aby zdefiniować katamorfizm, sposób na złożenie struktury danych, gdy podano jedną funkcję dla każdego z możliwych konstruktorów.
Na przykład dla Bool
catamorphism jest
bool :: a -> a -> Bool -> a
bool x _ False = x
bool _ y True = y
i Either
to
either :: (a -> c) -> (b -> c) -> Either a b -> c
either f g (Left x) = f x
either f g (Right x) = g x
Bardziej zaawansowany catamorphism jest jeden na listach, które masz prawdopodobnie widział: foldr
!
foldr :: (a -> b -> b) -> b -> [a] -> b
foldr f init [] = init
foldr f init (x:xs) = f x (foldr f init xs)
Zwykle nie myśleć o tym w ten sposób (lub przynajmniej nie mam), ale foldr
jest catamorphism: obsługuje wzorzec dopasowywania i rekurencyjnie dekonstrukcji listę dla ciebie, tak długo jak ty zapewnienie „ładowarki” dla wartości znajdujących się w dwóch konstruktorów [a]
:
- Jeden przypadek obsłużyć
[]
, potrzebując żadnych argumentów na wszystkich: tylko wartość typu b
- jednym przypadku do obsługi
(x:xs)
. Przypadek ten przyjmuje jeden argument reprezentujący x
, nagłówek listy i jeden argument reprezentujący wynik złożenia rekurencyjnie rekina, o wartości typu b
.
catamorphism jest mniej ekscytujące dla typu z tylko jeden konstruktor, ale możemy łatwo określić dla swojego typu Keypress
:
key :: (Int -> Char -> a) -> Keypress -> a
key f (Keypress x c) = f x c
W sposób catamorphism pozwala streszczenie dala wzór -matchowanie części definicji funkcji, po czym można po prostu pracować z funkcjami, które nie muszą już bezpośrednio dotykać bazowego typu danych.
Po zdefiniowaniu tej ogólnie użytecznej funkcji jeden raz, możesz użyć jej wiele razy, aby zaimplementować dowolną funkcję bez punktu, której pragnie twoje serce. W twoim przypadku możesz po prostu napisać:
getSeq :: Keypress -> [Char]
getSeq = key replicate