Generalization of Named

I introduced the Named data in my last article, and I tried to generalize a bit.

I came to the Civility idea and more, the Citizen data. They are some information that define an object in a context, but does not define entirely it (like a Name: it identify yourself as a citizen, but not has a Human being). So a Citizen is something with its papers:

data Citizen a b = Citizen
{
  papers :: a,
  obj :: b
}

But that is likely a tuple, and in fact, all the previous instances are correctly defined for Tuples!

So in-fine we have

type Citizen a b = (a,b)
type Named a = (String,a)

More results than the ones on the previous-Named ?

Monads and CoMonads together ?

Some pretty results are coming if the papers are an instance of a Monoid: We have Applicative and Monad instances:

instance Monoid a => Applicative ((,) a) where
    pure x = (mempty, x)
    (u, f) <*> (v, x) = (u <> v, f x)
    liftA2 f (u, x) (v, y) = (u <> v, f x y)

instance Monoid a => Monad ((,) a) where
    (u, a) >>= k = case k a of (v, b) -> (u <> v, b)

Theses samples of code are took from http://hackage.haskell.org/package/base-4.11.0.0/docs/src/GHC.Base.html#line-433

Basically, if there are empty papers and a way to concatenate them, Citizen become a Monad.

BiFunctor

Yes, you apply a function independently on papers and on the object, so you are also wining a BiFunctor instance

Utility: The Grouped example:

Grouped is a common data:

data Grouped a = Simple a | Group String [Grouped a]

You can find it in the Weigh package. It represents a kind of Rose Tree.

You can write a pretty function that transform the structure in a “after-parsing” one:

getDeepCitizen :: Grouped (Named a) -> [([String],a)]
getDeepCitizen (Simple (n,a))) = [([n],a)]
getDeepCitizen (Group str grp) = concatMap (map (join . ([str],)) . getDeepCitizen ) grp

Now imagine you have a tree :: Grouped (Named File) representing a file tree in a Unix system

Then you have:

printTree :: Grouped (Named File) -> IO ()
printTree t = mapM_ (putStrLn . intercalate "/" . fst) $ getDeepCitizen t

For example:

>>> printTree $ Group "" [Simple (withName "info.txt" ()), Group "bin" [Simple (withName "ghc" ()),Simple (withName "stack" ())]]

/info.txt
/bin/ghc
/bin/stack