I want to be able to use cata
from recursion-schemes
package for lists in Church encoding.
type ListC a = forall b. (a -> b -> b) -> b -> b
I used a second rank type for convenience, but I don't care. Feel free to add a newtype
, use GADTs, etc. if you feel it is necessary.
The idea of Church encoding is widely known and simple:
three :: a -> a -> a -> List1 a
three a b c = \cons nil -> cons a $ cons b $ cons c nil
Basically "abstract unspecified" cons
and nil
are used instead of "normal" constructors. I believe everything can be encoded this way (Maybe
, trees, etc.).
It's easy to show that List1
is indeed isomorphic to normal lists:
toList :: List1 a -> [a]
toList f = f (:) []
fromList :: [a] -> List1 a
fromList l = \cons nil -> foldr cons nil l
So its base functor is the same as of lists, and it should be possible to implement project
for it and use the machinery from recursion-schemes
.
But I couldn't, so my question is "how do I do that?". For normal lists, I can just pattern match:
decons :: [a] -> ListF a [a]
decons [] = Nil
decons (x:xs) = Cons x xs
Since I cannot pattern-match on functions, I have to use a fold to deconstruct the list. I could write a fold-based project
for normal lists:
decons2 :: [a] -> ListF a [a]
decons2 = foldr f Nil
where f h Nil = Cons h []
f h (Cons hh t) = Cons h $ hh : t
However I failed to adapt it for Church-encoded lists:
-- decons3 :: ListC a -> ListF a (ListC a)
decons3 ff = ff f Nil
where f h Nil = Cons h $ \cons nil -> nil
f h (Cons hh t) = Cons h $ \cons nil -> cons hh (t cons nil)
cata
has the following signature:
cata :: Recursive t => (Base t a -> a) -> t -> a
To use it with my lists, I need:
- To declare the base functor type for the list using
type family instance Base (ListC a) = ListF a
- To implement
instance Recursive (List a) where project = ...
I fail at both steps.