meta_leap
meta_leap

Reputation: 2185

How to construct a no-op IO() expression in Haskell?

Here's an excerpt of a domain-specific file-IO function I'm writing:

let
    cp :: FilePath -> IO ()
    cp "." = putStr "" -- OUCH!
    cp ".." = putStr "" -- CRIKEY!
    cp fname = custom logic here...
in mapM_ cp filepaths

I understand mapM_ lets us drop/ignore all IO () results, so I'd like a cleaner alternative to putStr "" --- ie. Haskell's "canonical" way to write "a type-correct no-op IO (or monad) expression that does nothing".

From my newbie reading I had undefined in mind, and while this compiles and causes no issues, it gives an unwanted stdout print main.hs: Prelude.undefined (I use stack runghc main.hs as the sole coding environment here --- it's just sufficient for this, but the above code will be looping recursively through directory trees: so would be a good time to (re)learn about a better, or rather "the proper" way).

Upvotes: 6

Views: 1794

Answers (1)

hao
hao

Reputation: 10238

This is an unfortunate aspect of Haskell's learning curve: you would think there should be some sort of library function called

doNothing :: IO ()

for you to use, but the ecosystem expects you to know of the return function in the Monad typeclass, one of the many typeclasses that IO instances. In this case return () should produce the intended behavior of creating an IO action (read: effect, or thunk, or promise) that does nothing.

You might also be interested in listDir and copyFile from the path-io package, which by using stronger types than type FilePath = String is able to do away with the whole problem of . and .. altogether. Note in particular how listDir returns subdirectories and files separately in a tuple. If that is not in the spirit of Haskell then what is? It does bring in an external dependency however but I am always looking for situations to plug that excellent library.

Upvotes: 11

Related Questions