I'm playing around with some recursion schemes, namely catamorphisms and anamorphisms, and would like to try to implement a solution to the lattice paths algorithm as described below using them (taken from a collection of interview questions):
Prompt: Count the number of unique paths to travel from the top left
order to the bottom right corner of a lattice of M x N squares.
When moving through the lattice, one can only travel to the
adjacent corner on the right or down.
Input: m {Integer} - rows of squares
Input: n {Integer} - column of squares
Output: {Integer}
Example: input: (2, 3)
(2 x 3 lattice of squares)
__ __ __
|__|__|__|
|__|__|__|
output: 10 (number of unique paths from top left corner to bottom right)**
Using normal recursion, you could solve this with something like:
lattice_paths m n =
if m == 0 and n == 0 then 1
else if m < 0 or n < 0 then 0
else (lattice_paths (m - 1) n) + lattice_paths m (n - 1)
My Fix
, cata
and ana
are defined as follows:
newtype Fix f = In (f (Fix f))
deriving instance (Eq (f (Fix f))) => Eq (Fix f)
deriving instance (Ord (f (Fix f))) => Ord (Fix f)
deriving instance (Show (f (Fix f))) => Show (Fix f)
out :: Fix f -> f (Fix f)
out (In f) = f
-- Catamorphism
type Algebra f a = f a -> a
cata :: (Functor f) => Algebra f a -> Fix f -> a
cata f = f . fmap (cata f) . out
-- Anamorphism
type Coalgebra f a = a -> f a
ana :: (Functor f) => Coalgebra f a -> a -> Fix f
ana f = In . fmap (ana f) . f
The approach mentioned in this post (https://stackoverflow.com/a/56012344) for writing recursion schemes that go from Int -> Int, is to write a hylomorphism where the anamorphism sort of builds the call stack and the catamorphism the evaluation of said callstack. I'm not sure how to build the call stack here.