Skip to content

Instantly share code, notes, and snippets.

@guibou
Forked from coodoo/Interop.hs
Last active December 9, 2017 23:26
Show Gist options
  • Select an option

  • Save guibou/900da1e3740b7b3804f4d6b6778c4cb8 to your computer and use it in GitHub Desktop.

Select an option

Save guibou/900da1e3740b7b3804f4d6b6778c4cb8 to your computer and use it in GitHub Desktop.

Revisions

  1. guibou revised this gist Dec 9, 2017. 1 changed file with 44 additions and 54 deletions.
    98 changes: 44 additions & 54 deletions Interop.hs
    Original file line number Diff line number Diff line change
    @@ -3,7 +3,6 @@
    - Read all folders and sub-folders with structure like below
    - store all folder and file info in State monad,
    - at the end of the loop, print it.
    ├── aaa
    │ ├── b
    │ │ ├── b1
    @@ -17,27 +16,30 @@
    │ └── c2
    Goal: to practice using State and IO monad together by leveraging liftIO and unsafePerformIO
    Would appreciate any correction, better way to do it or generic advices
    -}
    module Main where

    import Control.Monad.State
    import Control.Monad.State
    import System.Directory
    import System.Exit
    import System.FilePath
    import Data.Time

    import Control.Monad.Extra (partitionM)

    main :: IO ([Dir], [File], Root)
    main :: IO ([Dir], [File])
    main
    = do
    ~(_, s@(d, f, r)) <- runStateT k ([], [], "aaa")
    putStrLn $ "Root: " ++ r
    let root = "/tmp/poulet"
    s@(d, f) <- k root
    putStrLn $ "Root: " ++ root

    pretty d True "DIR:"
    pretty f True "FILE:"
    return s

    -- | Order is arbitrary
    pretty :: Show a => [a] -> Bool -> String -> IO ()
    pretty src rev prefix = do
    putStrLn $ "\n" ++ prefix ++ "\n"
    @@ -47,60 +49,48 @@ pretty src rev prefix = do

    data File = File
    { name :: String
    , date :: String
    , date :: UTCTime
    , size :: Integer
    , content :: String
    } deriving (Show)

    data Dir = Dir
    { dirName :: String
    , dirDate :: String
    , dirDate :: UTCTime
    , dirContent :: [FilePath]
    } deriving (Show)

    type Root = String
    k :: String -> IO ([Dir], [File])
    k root = do
    isDir <- doesDirectoryExist root
    unless isDir $ die "not a dir"
    execStateT (list root) ([], [])

    list :: String -> StateT ([Dir], [File]) IO ()
    list path = do
    -- walk current directory
    dir <- liftIO $ do
    children <- listDirectory path
    dt <- getModificationTime path
    return Dir {dirName = path, dirContent = children, dirDate = dt}
    modify (\(ds, fs) -> (dir : ds, fs))

    -- remove unwanted files and prepend directory name
    let
    fullPaths = map (path</>) (dirContent dir)
    filteredFiles = filter (/=".DS_Store") fullPaths

    -- Split between sub directories and sub files
    (subDirs, subFiles) <- liftIO (partitionM doesDirectoryExist filteredFiles)

    -- recursivly walk sub directories
    forM_ subDirs list

    k :: StateT ([Dir], [File], Root) IO ()
    k = do
    (_, _, root) <- get
    liftIO $ do
    isDir <- doesDirectoryExist root
    unless isDir $ die "not a dir"
    list root
    where
    list :: String -> StateT ([Dir], [File], Root) IO ()
    list path = do
    dir <-
    liftIO $
    do
    children <- withCurrentDirectory path $ listDirectory "."
    dt <- getModificationTime path
    return Dir {dirName = path, dirContent = children, dirDate = show dt}
    _ <- withStateT (\(ds, fs, root) -> (dir : ds, fs, root)) get
    n <-
    liftIO $
    foldM
    (\acc@(dirs, files) f -> do
    let fullPath = path </> f
    if (f == ".DS_Store")
    then return acc
    else do
    bool <- doesDirectoryExist fullPath
    if bool
    then return (dirs ++ [fullPath], files)
    else return (dirs, files ++ [fullPath]))
    ([], []) -- acc, ([dirs], [files])
    $
    dirContent dir
    forM_ (fst n) list
    files <-
    liftIO $
    mapM
    (\f -> do
    s <- getFileSize f
    dt <- getModificationTime f
    c <- readFile f
    return File {name = f, date = show dt, size = s, content = c})
    (snd n)
    _ <- withStateT (\(ds, fs, root) -> (ds, files ++ fs, root)) get
    return ()
    -- handle files in the current directory
    forM_ subFiles $ \f -> do
    file <- liftIO $ do
    s <- getFileSize f
    dt <- getModificationTime f
    c <- readFile f
    return File {name = f, date = dt, size = s, content = c}
    modify (\(ds, fs) -> (ds, file:fs))
  2. @coodoo coodoo created this gist Dec 9, 2017.
    106 changes: 106 additions & 0 deletions Interop.hs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,106 @@
    {-
    Functionality:
    - Read all folders and sub-folders with structure like below
    - store all folder and file info in State monad,
    - at the end of the loop, print it.
    ├── aaa
    │ ├── b
    │ │ ├── b1
    │ │ │ ├── b1-1
    │ │ │ └── b1-2
    │ │ └── b2
    │ │ └── 2-1
    │ │ └── b2-1-1
    │ └── c
    │ ├── c1
    │ └── c2
    Goal: to practice using State and IO monad together by leveraging liftIO and unsafePerformIO
    Would appreciate any correction, better way to do it or generic advices
    -}
    module Main where

    import Control.Monad.State
    import Control.Monad.State
    import System.Directory
    import System.Exit
    import System.FilePath

    main :: IO ([Dir], [File], Root)
    main
    = do
    ~(_, s@(d, f, r)) <- runStateT k ([], [], "aaa")
    putStrLn $ "Root: " ++ r
    pretty d True "DIR:"
    pretty f True "FILE:"
    return s

    pretty :: Show a => [a] -> Bool -> String -> IO ()
    pretty src rev prefix = do
    putStrLn $ "\n" ++ prefix ++ "\n"
    if rev
    then mapM_ print $ reverse src
    else mapM_ print src

    data File = File
    { name :: String
    , date :: String
    , size :: Integer
    , content :: String
    } deriving (Show)

    data Dir = Dir
    { dirName :: String
    , dirDate :: String
    , dirContent :: [FilePath]
    } deriving (Show)

    type Root = String

    k :: StateT ([Dir], [File], Root) IO ()
    k = do
    (_, _, root) <- get
    liftIO $ do
    isDir <- doesDirectoryExist root
    unless isDir $ die "not a dir"
    list root
    where
    list :: String -> StateT ([Dir], [File], Root) IO ()
    list path = do
    dir <-
    liftIO $
    do
    children <- withCurrentDirectory path $ listDirectory "."
    dt <- getModificationTime path
    return Dir {dirName = path, dirContent = children, dirDate = show dt}
    _ <- withStateT (\(ds, fs, root) -> (dir : ds, fs, root)) get
    n <-
    liftIO $
    foldM
    (\acc@(dirs, files) f -> do
    let fullPath = path </> f
    if (f == ".DS_Store")
    then return acc
    else do
    bool <- doesDirectoryExist fullPath
    if bool
    then return (dirs ++ [fullPath], files)
    else return (dirs, files ++ [fullPath]))
    ([], []) -- acc, ([dirs], [files])
    $
    dirContent dir
    forM_ (fst n) list
    files <-
    liftIO $
    mapM
    (\f -> do
    s <- getFileSize f
    dt <- getModificationTime f
    c <- readFile f
    return File {name = f, date = show dt, size = s, content = c})
    (snd n)
    _ <- withStateT (\(ds, fs, root) -> (ds, files ++ fs, root)) get
    return ()