Skip to content

Instantly share code, notes, and snippets.

@bcachet
Created July 3, 2017 21:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bcachet/ba0286d4526f4f3bba2df145f6ddd12d to your computer and use it in GitHub Desktop.
Save bcachet/ba0286d4526f4f3bba2df145f6ddd12d to your computer and use it in GitHub Desktop.
#load "Tree.fs"
open Tree
open System
open System.IO
type FileSystemTree = Tree<IO.FileInfo,IO.DirectoryInfo>
let fromFile (fileInfo:FileInfo) =
LeafNode fileInfo
let rec fromDir (dirInfo:DirectoryInfo) =
let subItems = seq{
yield! dirInfo.EnumerateFiles() |> Seq.map fromFile
yield! dirInfo.EnumerateDirectories() |> Seq.map fromDir
}
InternalNode (dirInfo,subItems)
let [<Literal>] dataDir = __SOURCE_DIRECTORY__ + "\Data"
let c = dataDir |> DirectoryInfo |> fromDir
let dirListing fileSystemItem =
let printDate (d:DateTime) = d.ToString()
let mapFile (fi:FileInfo) =
sprintf "%10i %s %-s" fi.Length (printDate fi.LastWriteTime) fi.Name
let mapDir (di:DirectoryInfo) =
di.FullName
Tree.map mapFile mapDir fileSystemItem
let rec isEmpty (directory:DirectoryInfo) =
let files = directory.GetFiles()
let dirs = directory.GetDirectories()
(Array.fold (fun v d -> v && (isEmpty d)) (Array.isEmpty files) dirs)
c
|> Tree.filter (fun l -> true) (not << isEmpty)
|> Option.get
|> dirListing
module Tree
type Tree<'LeafData,'INodeData> =
| LeafNode of 'LeafData
| InternalNode of 'INodeData * Tree<'LeafData,'INodeData> seq
let rec filter fLeaf fNode (tree : Tree<'LeafData,'INodeData>) =
let recurse = filter fLeaf fNode
match tree with
| LeafNode (info) ->
if fLeaf(info) then
Some(LeafNode(info))
else
None
| InternalNode (info, children) ->
if fNode(info) then
Some(InternalNode(info, children |> Seq.map recurse |> Seq.where Option.isSome |> Seq.map Option.get))
else
None
let rec fold fLeaf fNode acc (tree:Tree<'LeafData,'INodeData>) :'r =
let recurse = fold fLeaf fNode
match tree with
| LeafNode leafInfo ->
fLeaf acc leafInfo
| InternalNode (nodeInfo,subtrees) ->
// determine the local accumulator at this level
let localAccum = fNode acc nodeInfo
// thread the local accumulator through all the subitems using Seq.fold
let finalAccum = subtrees |> Seq.fold recurse localAccum
// ... and return it
finalAccum
let rec map fLeaf fNode (tree:Tree<'LeafData,'INodeData>) =
let recurse = map fLeaf fNode
match tree with
| LeafNode leafInfo ->
let newLeafInfo = fLeaf leafInfo
LeafNode newLeafInfo
| InternalNode (nodeInfo,subtrees) ->
let newNodeInfo = fNode nodeInfo
let newSubtrees = subtrees |> Seq.map recurse
InternalNode (newNodeInfo, newSubtrees)
let rec iter fLeaf fNode (tree:Tree<'LeafData,'INodeData>) =
let recurse = iter fLeaf fNode
match tree with
| LeafNode leafInfo ->
fLeaf leafInfo
| InternalNode (nodeInfo,subtrees) ->
subtrees |> Seq.iter recurse
fNode nodeInfo
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment