crux-0.7: src/Crux/Loops.hs
module Crux.Loops where
import qualified Data.Map as Map
data Tree a = Node { node :: a, children :: Forest a }
deriving Show
type Forest a = [Tree a]
findLoops :: Eq a => [a] -> Forest a
findLoops = go []
where
go prev steps =
case steps of
[] -> reverse prev
x : xs ->
case break ((x ==) . node) prev of
(inner,_:prev') -> go (Node x [] : Node x (reverse inner) : prev') xs
_ -> go (Node x [] : prev) xs
annotate :: Ord a => Forest a -> [ ([Int],a) ]
annotate = go [] Map.empty [] []
where
go ns iters prevIters rest todo =
case todo of
[] -> rest
tree : trees ->
let a = node tree
n = Map.findWithDefault 1 a iters
ns' = n : ns
rest' = go ns (Map.insert a (n+1) iters) prevIters rest trees
in (reverse ns', a) :
go ns' Map.empty (iters : prevIters) rest' (children tree)
annotateLoops :: Ord a => [a] -> [ ([Int],a) ]
annotateLoops = annotate . findLoops