[Haskell-cafe] Test on identity?
Olaf Klinke
olf at aatal-apotheke.de
Wed Jul 8 21:26:11 UTC 2020
> Dear Café,
>
> I'm trying to build a DAG from a binary tree. I don't think there's a
> big trouble.
> Nevertheless, I do even some transformations. Thus, I would like to
> know it is still a
> DAG, not adding, accidentally, a node.
>
> Is there any way, if I have data like
>
> data Ex
> = Val Int
> | Add Ex Ex
>
> so that I can test that some value Val i === Val i ? I mean, the
> pointers go to the
> same data box? I could do that via some IORefs, AFAIK, but I don't
> think it is
> feasible. Maybe to tune the algorithm...
>
> Best regards,
>
> Dusan
So the binary tree is a value e :: Ex, right? And the DAG (directed
acyclic graph) is an explicit representation of the internal pointer
structure in e? Did I understand you right?
This sounds like you should represent Ex as a fixed point and then
invoke some fixed point magic like catamorphisms. Your transformation
might have to be re-written as a cata/ana/hylomorphism, too. Below is a
recipe to turn any element of any fixed point type into a graph, that
is, into a list of nodes and edges. Of course this will loop if your
data was not a finite DAG, e.g. due to self-reference.
-- make type recursion for your type Ex explicit
data ExF x = Val Int | Add x x deriving (Show)
instance Functor ExF where
fmap f (Val i) = Val i
fmap f (Add x y) = Add (f x) (f y)
instance Foldable ExF where
foldMap _ (Val _) = mempty
foldMap f (Add x y) = f x <> f y
instance Traversable ExF where
traverse f (Val i) = pure (Val i)
traverse f (Add x y) = Add <$> (f x) <*> (f y)
-- represent Ex via the general
-- Fix :: (* -> *) -> *
-- See e.g. package data-fix or recursion-schemes
-- cataM below taken from the data-fix package
type Ex = Fix ExF -- = Fix {unFix :: ExF (Fix ExF)}
-- Add () () tells you the node is internal
type ExNode = ExF ()
data GraphElem f = Node Int (f ()) | Edge Int Int
instance Show (GraphElem ExF) where
show (Node n (Val i)) = show n ++ ":Val " ++ show i
show (Node n (Add _ _)) = show n ++ ":Add"
show (Edge i j) = show i ++ " -> " ++ show j
type Graph = [GraphElem ExF]
type GraphM = StateT Int (Writer Graph)
structure :: (Traversable f,
MonadState Int m,
MonadWriter [GraphElem f] m) =>
f Int -> m Int
structure fi = do
this <- get
tell [Node this (void fi)]
traverse (\child -> tell [Edge this child]) fi
put (this+1)
return this
-- depth-first traversal. More generally dag has type
-- (Traversable f) => Fix f -> [GraphElem f]
-- and the Traversable instance determines the order
-- of the traversal.
dag :: Ex -> Graph
dag = snd . runWriter . flip evalStateT 0 . cataM structure
-- Cheers, Olaf
More information about the Haskell-Cafe
mailing list