Skip to content

Instantly share code, notes, and snippets.

@snowmantw
Created November 4, 2017 02:25
Show Gist options
  • Save snowmantw/f566ba25d3579b23205bcaffb806ea14 to your computer and use it in GitHub Desktop.
Save snowmantw/f566ba25d3579b23205bcaffb806ea14 to your computer and use it in GitHub Desktop.
List to "Tree" in State Monad
module StateTree ( buildTree ) where
import Prelude hiding (lookup)
import Control.Monad.State
import Data.Map (Map, insert, insertWith, empty, lookup)
data Item = Item {
sId :: String,
pId :: String,
value :: [Char],
children :: [String]
} deriving (Show)
list :: [] Item
list = [ Item { sId="1", pId="0", value="1", children=[] }
, Item { sId="1-1", pId="1", value="1-1", children=[] }
, Item { sId="1-2", pId="1", value="1-2", children=[] }
, Item { sId="2", pId="0", value="2", children=[] }
, Item { sId="2-1", pId="2", value="2-1", children=[] }
, Item { sId="2-2", pId="2", value="2-2", children=[] }
]
type Table = Map String Item
root = Item { sId="0", pId="-1", value="root node", children=[] }
-- Make "state lines" for each Item in the list.
buildStatement :: Item -> State Table ()
buildStatement item =
state $ \tree -> ((), (mergeNode tree item))
-- insert the item into the map and update the children if pId matches
mergeNode :: Table -> Item -> Table
mergeNode tree item =
case lookup (pId item) tree of
Just treeItem -> insert (sId item) item parentUpdated
Nothing -> insert (sId item) item tree -- top root
where
parentUpdated = insertWith mergeToParent (pId item) item tree -- -> map updated
mergeToParent child parent = parent { children = children parent ++ [sId child] }
statements :: [] Item -> State Table ()
statements items =
foldl folder initStatement items
where initStatement = buildStatement root
folder sts item = sts >>= (\_ -> buildStatement item)
buildTree :: ((), Table)
buildTree = runState (statements list) empty
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment