I want to write some functions that work over all data types in Haskell (at least all instances of Data from Data.Data). A general problem I ran into is making a choice of what to do based on whether the constructor is recursive or not -- by recursive constructor I mean the data type is D and the there is a constructor C one of whose arguments is a D.
I can solve the above problem by solving a simpler problem: given a data, determine whether the outermost constructor is recursive.
Here is attempt number 1:
data B a = T | F
gIsLeafCons :: (Data a) => a -> B a
gIsLeafCons m = gfoldl (\x y -> F) (\x -> T) m
The idea is that if the constructor is recursive, then we return F else we return T. This works great at first glance:
gIsLeafCons 1 ==> T
gIsLeafCons ([] :: [Int]) ==> T
However, gfoldl is polymorphic, so given a tree data type such as
data Tree a = Leaf a | Node (Tree a) (Tree a)
We fail.
gIsLeafCons (Leaf 1) ==> F
The reason is that (Leaf 1) is not a truly empty constructor: it has the argument 1, and so the constructor function (\x y -> F) is applied.
Attempt number 2:
We could go with a "leaf constructor" is one where all children evaluate to F. This is a slight improvement:
gIsLeafByChild (Leaf 1) ==> T
However, if the leaves hold a different recursive structure; this will again fail.
gIsLeafByChild (Leaf (Leaf 1)) ==> F
I really want to stop at the first "leaf constructor" but gfoldl's polymorphic nature makes it seem hard to do this, as seen above.
So finally, is there a way to coax out whether a constructor is a "leaf constructor" or not. My current solution is to have a user pass in a list of leaf constructors ([Constr]), and I just check if the constructor is one of these. However, it would be nice to automatically infer if something would be in this list.
data T = T Int F; data F = F Int T
, for example. This could reasonably be considered recursive or "leaf". – amalloyConstant
fromData.Constant.Functor
in the transformers package. hackage.haskell.org/package/transformers-0.4.1.0/docs/… It captures the idea of yourB a
type in general, for example,B a
would beConstant Bool a
. – Cirdec