3
\$\begingroup\$

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.

200_success
146k22 gold badges190 silver badges479 bronze badges
asked Jan 31, 2015 at 15:10
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

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 Monads.

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
answered Jan 31, 2015 at 21:12
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.