packages feed

neuron-0.4.0.0: src/lib/Data/PathTree.hs

{-# LANGUAGE NoImplicitPrelude #-}

module Data.PathTree
  ( mkTreeFromPaths,
    annotatePathsWith,
    foldSingleParentsWith,
  )
where

import qualified Data.List.NonEmpty as NE
import qualified Data.Map as Map
import Data.Tree
import Relude
import Relude.Extra.Group

mkTreeFromPaths :: Ord a => [[a]] -> Forest a
mkTreeFromPaths paths = uncurry mkNode <$> Map.assocs groups
  where
    groups = fmap tail <$> groupBy head (mapMaybe nonEmpty paths)
    mkNode label children =
      Node label $ mkTreeFromPaths $ toList children

annotatePathsWith :: (NonEmpty a -> ann) -> Tree a -> Tree (a, ann)
annotatePathsWith f = go []
  where
    go ancestors (Node rel children) =
      let path = rel :| ancestors
       in Node (rel, f $ NE.reverse path) $ fmap (go $ toList path) children

-- | Fold nodes with one child using the given function
--
-- The function is called with the parent and the only child. If a Just value is
-- returned, folding happens with that value, otherwise there is no effect.
foldSingleParentsWith :: (a -> a -> Maybe a) -> Tree a -> Tree a
foldSingleParentsWith f = go
  where
    go (Node parent children) =
      case fmap go children of
        [Node child grandChildren]
          | Just new <- f parent child -> Node new grandChildren
        xs -> Node parent xs