This is what I've done;
import Control.Applicative
import Control.Monad
import qualified System.Directory as SD
main = do
files <- SD.getDirectoryContents =<< SD.getCurrentDirectory
exes <- filterM (liftA SD.executable <$> SD.getPermissions) files
print exes
This works fine, but I can't help feeling that this code is somewhat redundant --- with filterM
, liftA
, <$>
and =<<
all present at once, things seem unnecessarily complicated.
How can I improve this piece of code?
For a quick reference:
SD.getCurrentDirectory :: IO FilePath
SD.getDirectoryContents :: FilePath -> IO [FilePath]
SD.executable :: Permissions -> Bool
SD.getPermissions :: FilePath -> IO Permissions
and I want to filter the contents of the current directory based on its being executable or not.
1 Answer 1
I wouldn't import System.Directory
qualified, it doesn't export anything that could clash with standard names.
import Control.Applicative
import Control.Monad
import System.Directory
main :: IO ()
main = do
files <- getDirectoryContents =<< getCurrentDirectory
exes <- filterM (liftA executable <$> getPermissions) files
print exes
You can toss out the Functor
and Applicative
stuff and just compose Monad
s.
import Control.Monad
import System.Directory
main :: IO ()
main = do
files <- getDirectoryContents =<< getCurrentDirectory
exes <- filterM (liftM executable . getPermissions) files
print exes
You could also get rid of reverse bind and use the forward version, it's maybe more familiar?
import Control.Monad
import System.Directory
main :: IO ()
main = do
files <- getCurrentDirectory >>= getDirectoryContents
exes <- filterM (liftM executable . getPermissions) files
print exes
I'd eliminate the explicit use of bind entirely though, then it becomes easier to turn this into a function that can work on directories other than the current one.
import Control.Monad
import System.Directory
main :: IO ()
main = do
dir <- getCurrentDirectory
printExecutables dir
printExecutables :: FilePath -> IO ()
printExecutables dir = do
files <- getDirectoryContents dir
exes <- filterM (liftM executable . getPermissions) files
print exes