Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 803
metaleap Avatar asked May 25 '16 19:05

metaleap


People also ask

What is IO () Haskell?

IO is the way how Haskell differentiates between code that is referentially transparent and code that is not. IO a is the type of an IO action that returns an a . You can think of an IO action as a piece of code with some effect on the real world that waits to get executed.

How is Haskell IO implemented?

It's implemented using unsafeInterleaveIO , which does trickery behind the scenes to allow lazy I/O. It's not a good example of how IO is supposed to work.

What is an I/O action?

I/O actions are ordinary Haskell values: they may be passed to functions, placed in structures, and used as any other Haskell value. Consider this list of actions: todoList :: [IO ()]

What does >> mean in Haskell?

Essentially, a >> b can be read like "do a then do b , and return the result of b ". It's similar to the more common bind operator >>= .


1 Answers

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.

like image 170
hao Avatar answered Oct 20 '22 06:10

hao