Scrapbook-0.4.0: code examples
Copyright© Frank Jung 2021-2023
LicenseGPL-3
Safe HaskellSafe-Inferred
LanguageHaskell2010

RecursionSchemes

Description

A collection of recursion scheme examples.

Examples

Anamorphism

Using a non-recursive coalgebra to create a ListF.

test = buildListF 4
show test
"ConsF 4 (ConsF 3 (ConsF 2 (ConsF 1 NilF)))"

λ> :t unFix test
unFix test :: ListF Int (Fix (ListF Int))

λ> :t test
test :: Fix (ListF Int)

Catamorphism

Using a non-recursive algebra to measure length of ListF entry, use a catamorphism over the alegra to measure length of the entire ListF.

test :: Int a => Fix (ListF a)
test = Fix (ConsF 4 (Fix (ConsF 3 (Fix (ConsF 2 (Fix (ConsF 1 (Fix NilF))))))))

lengthListF test
4

Paramorphism

The paramorphism examples come from "Making Sense of Recursion Patterns". A paramorphism is like a catamorphism, but it preserves the initial data structure.

References

Synopsis

Data constructors

newtype Fix f Source #

Generalised fixed point for any functor f. Note that unFix (Fix x) == x

Constructors

Fix 

Fields

Instances

Instances details
Show (f (Fix f)) => Show (Fix f) Source # 
Instance details

Defined in RecursionSchemes

Methods

showsPrec :: Int -> Fix f -> ShowS #

show :: Fix f -> String #

showList :: [Fix f] -> ShowS #

Eq (f (Fix f)) => Eq (Fix f) Source # 
Instance details

Defined in RecursionSchemes

Methods

(==) :: Fix f -> Fix f -> Bool #

(/=) :: Fix f -> Fix f -> Bool #

data ListF a r Source #

List Functor where r is the carrier type.

Constructors

NilF 
ConsF a r 

Instances

Instances details
Functor (ListF a) Source # 
Instance details

Defined in RecursionSchemes

Methods

fmap :: (a0 -> b) -> ListF a a0 -> ListF a b #

(<$) :: a0 -> ListF a b -> ListF a a0 #

(Show a, Show r) => Show (ListF a r) Source # 
Instance details

Defined in RecursionSchemes

Methods

showsPrec :: Int -> ListF a r -> ShowS #

show :: ListF a r -> String #

showList :: [ListF a r] -> ShowS #

(Eq a, Eq r) => Eq (ListF a r) Source # 
Instance details

Defined in RecursionSchemes

Methods

(==) :: ListF a r -> ListF a r -> Bool #

(/=) :: ListF a r -> ListF a r -> Bool #

data NatF r Source #

Natural numbers Functor.

Constructors

ZeroF 
SuccF r 

Instances

Instances details
Functor NatF Source # 
Instance details

Defined in RecursionSchemes

Methods

fmap :: (a -> b) -> NatF a -> NatF b #

(<$) :: a -> NatF b -> NatF a #

Show r => Show (NatF r) Source # 
Instance details

Defined in RecursionSchemes

Methods

showsPrec :: Int -> NatF r -> ShowS #

show :: NatF r -> String #

showList :: [NatF r] -> ShowS #

type Nat = Fix NatF Source #

Natural numbers type.

type RAlgebra f a = Fix f -> f a -> a Source #

The code defines a type synonym RAlgebra that represents a recursive algebra for a functor f. An R-algebra is a function that takes a fixed point of a functor Fix f and a value of type f a, and returns a value of type a.

The Fix type is used to define recursive data structures in Haskell. It is a type constructor that takes a functor f as an argument and returns a fixed point of f. The Fix type is used to define recursive data structures by wrapping a value of type f (Fix f) in a Fix constructor.

The RAlgebra type synonym is used to define a function that takes a fixed point of a functor Fix f and a value of type f a, and returns a value of type a. This function is used to define recursive functions that operate on data structures defined using Fix.

The RAlgebra type synonym is a higher-order type that takes two type arguments: f, which is a functor, and a, which is the return type of the algebra. The RAlgebra type synonym is used to define recursive functions that operate on data structures defined using Fix.

Recursion schemes

ana :: Functor f => (a -> f a) -> a -> Fix f Source #

Anamorphism - produce a structure.

cata :: Functor f => (f a -> a) -> Fix f -> a Source #

Catamorphism - consume a structure.

para :: Functor f => RAlgebra f a -> Fix f -> a Source #

Paramorphism - improved consumption of a structure.

para' :: (a -> [a] -> b -> b) -> b -> [a] -> b Source #

Paramorphism where input list is the first parameter. This comes from Making Sense of Recursion Patterns by Paul Bailes and Leighton Brough. It extends foldr by supplying to the combining operation (op) the unprocessed list tail, in addition to the head and the result of recursion on the tail as provided by foldr.

Sum a list:

>>> para' (const . (+)) 0 [1,2,3]
6

Suffixes of a list:

>>> para' (const (:)) [] "abcd"
["bcd","cd","d",""]

para'' :: (a -> [a] -> b -> b) -> b -> [a] -> b Source #

Paramorphism using foldr. This comes from Making Sense of Recursion Patterns by Paul Bailes and Leighton Brough.

The following shows how to get a catamorphism from a paramorphism. In this example, we are calculating the sum of items from a list.

Sum a list:

>>> para'' (const . (+)) 0 [1,2,3]
6

Suffixes of a list:

>>> para'' (\ _ xs xss -> xs : xss) [] "abcd"
["bcd","cd","d",""]
>>> para'' (const (:)) [] "abcd"
["bcd","cd","d",""]

Coalgebra's

buildListF :: Int -> Fix (ListF Int) Source #

Feed coalgebra to anamorphism. This will build a list.

>>> buildListF 4 :: Fix (ListF Int)
ConsF 4 (ConsF 3 (ConsF 2 (ConsF 1 NilF)))

buildCoalg :: Int -> ListF Int Int Source #

Coalgebra is a non-recursive function to generate a ListF entry.

Algebra's

lengthAlg :: ListF a Int -> Int Source #

An alegbra over ListF to get list length.

lengthListF :: Fix (ListF a) -> Int Source #

Length is a folding operation, i.e. a Catamorphism.

>>> (lengthListF . buildListF) 4
4

lengthListF' :: Fix (ListF a) -> Int Source #

Length using special case of paramorphism.

>>> lengthListF' (buildListF 4)
4

fromNat :: Nat -> Int Source #

Convert Natural number to an integer.

>>> fromNat (toNat 4)
4

toNat :: Int -> Nat Source #

Build a natural number from an interger.

>>> toNat 4
SuccF (SuccF (SuccF (SuccF ZeroF)))

Utilities

insert :: Ord a => a -> [a] -> [a] Source #

Insert element into list at correct ordered position using foldr.

>>> insert 1 [2,3,4]
[1,2,3,4]
>>> insert 'c' "abde"
"abcde"
>>> insert 'f' "abcde"
"abcdef"
>>> insert 'o' "oa"
"ooa"

insert' :: Ord a => a -> [a] -> [a] Source #

Insert element into list at correct ordered position.

>>> insert' 1 [2,3,4]
[1,2,3,4]
>>> insert' 1 []
[1]
>>> insert' 'c' "abde"
"abcde"
>>> insert' 'c' "abde" == "abcde"
True
>>> insert' 'o' "oa"
"ooa"

toList :: Fix (ListF a) -> [a] Source #

Convert a ListF to a standard list.

idx0 :: (Foldable t, Num b) => t a -> [b] Source #

Indexing a list.

>>> idx0 "abcde"
[0,1,2,3,4]

idx1 :: (Foldable t, Num b) => t a -> [b] Source #

Alternate list indexing using foldr.

>>> idx1 "abcde"
[0,1,2,3,4]

idx2 :: [b] -> [Integer] Source #

Alternate list indexing using zipWith.

>>> idx2 "abcde"
[0,1,2,3,4]

idx3 :: Foldable t => t a -> [Integer] Source #

List indexing using foldr.

>>> idx3 "abcde"
[0,1,2,3,4]

idx4 :: [b] -> [Integer] Source #

List indexing using foldr with parameter last.

>>> idx4 "abcde"
[0,1,2,3,4]