A Haskell function of type: IO String-> String

30,919

Solution 1

You can easily enough write a function that calls the readFile action, and passes the result to your index function.

readAndIndex fileName = do
    text <- readFile fileName
    return $ index text

However, the IO monad taints everything that uses it, so this function has the type:

readAndIndex :: FilePath -> IO [(String, [Integer])]

Solution 2

There is a very good reason why there is no such function.

Haskell has the notion of functional purity. This means that a function will always return the same result when called with the same parameters. The only place where IO is allowed is inside the IO monad.

If there was* a function

index :: IO String -> String

then we could suddenly do IO actions anywhere by calling, for example:

index (launchMissiles >> deleteRoot >> return "PWNd!")

Functional purity is a very useful feature that we don't want to lose, since it allows the compiler to reorder and inline functions much more freely, they can be sparked off to different cores without changing the semantics and it also gives the programmers a sense of security since if you can know what a function can and can't do from it's type.

* Actually there is such a function. It's called unsafePerformIO and it's called that for very, very good reasons. Do not use it unless you're 100% sure of what you are doing!

Solution 3

Well you cannot get rid of the IO monad part of IO String. That means you will have to make your function return IO [(String, [Integer])].

I recommend learning more about monads, but for now you can get away with the liftM function:

liftM index (readFile "input.txt")

liftM has this signature:

liftM :: Monad m => (a -> b) -> m a -> m b

It takes a non-monadic function and transforms it into a monadic function.

Solution 4

fmap index $ readFile "input.txt"

or

readFile "input.txt" >>= return . index

You may want to look into monad and functors

Share:
30,919
ChrisQuignon
Author by

ChrisQuignon

Updated on July 05, 2020

Comments

  • ChrisQuignon
    ChrisQuignon almost 4 years

    I wrote a bunch of code in Haskell to create an index of a text. The top function looks like this:

    index :: String -> [(String, [Integer])]
    index a = [...]
    

    Now I want to give this function a String read from a file:

    index readFile "input.txt"
    

    Which won't work because readFile is of type FilePath -> IO String.

    Couldn't match expected type 'String' against inferred type 'IO String'

    I see the error, but I can't find any function with type:

    IO String -> String
    

    I guess the key to success lies somewhere under some Monads, but I could not find a way to solve my problem.

  • R. Martinho Fernandes
    R. Martinho Fernandes over 14 years
    I would go as far as saying "Do not use it unless you're 200% sure of what you are doing", or, even simpler, "Do not".
  • alternative
    alternative about 13 years
    I would say the best use for unsafePerformIO is to shell out to some process that should always return the same thing. ie a system computation not natively supported by the standard library.
  • alternative
    alternative almost 13 years
    Adding to my old comment that I just found while browsing around SO: Also useful for FFI
  • drumfire
    drumfire about 9 years
    It's just a small sentence: "the IO monad taints everything that uses it". I did assume this was the case, but it's nice to see it confirmed now. Thanks ^^