Reputation: 4219
I have the fixed point functor defined as follows:
newtype Fix f =
Fix
{ unfix ::
f (Fix f)
}
I would like to define a function which takes a Fix f
and gives its Böhm-Beraducci encoding. So that should have the type:
cata :: Fix f -> (forall a. (f a -> a) -> a)
I can easily define a function like this but with the additional constraint that f
is a Functor
, but I'm struggling without that restriction.
Intuitively I want to take the AST and replace all instances of the Fix
constructor with an input function, however in practice that seems to require a Functor
instance for F
. But to my understanding the Böhm-Beraducci encoding should exist even when f
is not a Functor
.
I feel like I'm missing something simple here. Is there a definition I'm missing? If Functor
is truly required, why? When does the Böhm-Beraducci encoding require additional constraints like this?
Upvotes: 3
Views: 68
Reputation: 116139
From a quick look at the original paper, it looks like the Böhm-Berarducci encoding represent term algebras using System F types.
Term algebras essentially involve an implicit f
which is always a functor.
Haskell goes beyond that and allows type-level fixed points on any f
, even those which can not be turned into functors.
A famous example is the negative recursive type newtype R a = R { unR :: R a -> a }
. The Haskell type system allows this type definition. Using this R a
alone, and with no term-level recursion, we can derive fix :: forall a . (a -> a) -> a
(a short but non trivial exercise, by the way).
System F, by contrast, can not be that general. If we had R a
in System F, we would also have fix
, hence fix id :: forall a . a
could be used to inhabit any System F type. But we know System F is consistent, so that can not happen.
Upvotes: 2