{-# LANGUAGE PatternSynonyms #-} data Free f a = Pure a | Free (f (Free f a)) data ListF a b = Nil | Cons a b deriving (Show) type Way a b = Free (ListF a) b pattern End end = Pure end pattern Path path r = Free (Cons path r) showWay :: (Show a, Show b) => Way a b -> String showWay (End end) = show end showWay (Path path (End end)) = show path ++ " :| " ++ show end showWay (Path path r) = show path ++ " :> " ++ showWay r main :: IO () main = do putStrLn $ showWay $ Path "foo" $ Path "bar" $ End 0