haskellio-monadhaskeline

Unsafe IO Or: Haskeline and Directories


DISCLAIMER: I am somewhat new to Haskell.

I am writing an interpreter, or, in this context, a REPL. For that purpose I am using haskeline, which is nice for REPLs. It has the capability of storing the command line history within a file, which is also nice.

One problem I came across while working with it, though, is that it does not seem to expand "~" to the home directory, which means that I have to retrieve the home directory manually.

I could do it like this (and currently do):

-- | returns a fresh settings variable
addSettings :: Env -> Settings IO
addSettings env = Settings { historyFile = Just getDir
                           , complete = completeWord Nothing " \t" $
                                        return . completionSearch env
                           , autoAddHistory = True
                           }
    where
        getDir :: FilePath
        getDir = unsafePerformIO getHomeDirectory ++ "/.zepto_history"

But that uses unsafePerformIO, which makes me cringe. Do you know of a good and clean workaround that does not involve rewriting the whole function? This can be a haskeline feature I do not know of or something I just did not see.

Telling me there is no way around rewriting and rethinking it all is fine, too.

EDIT:

I know unsafePerformIO is bad, that's why it makes me cringe. If you are new to Haskell and reading this question right now: Just pretend it is not there.


Solution

  • A better approach would be to generate the Settings object inside IO, instead of the other way around, so to speak:

    addSettings :: Env -> IO (Settings IO)
    addSettings = do
        getDir <- fmap (++ "/.zepto_history") getHomeDirectory
        return $ Settings
            { historyFile = Just getDir
            , complete = completeWord Nothing " \t" $ return . completionSearch env
            , autoAddHistory = True
            }
    

    This will no doubt require some changes in your current software, but this would be considered the "right" way to go about this.