Hi,
Recently I wrote a code that uses readline library (System.Console.Readline).
I had to maintain a state (file path) and do IO throughout the code, so I decided to use StateT monad.
The problem was that in order to retrieve the current state (file path) inside the handler that had been registered by using bindKey function of readline, I had to resort back to using IORef rather than using the state stored in the StateT monad. It's because the handler for bindKey should have the type of Int -> Char -> IO Int.
Here is my code snippet.
type MyState a = StateT FilePath IO a
rootDir :: FilePath
rootDir = "/root/"
main :: IO ()
main = do hSetBuffering stdout NoBuffering
execStateT (do
pwd <- get
pwdRef <- lift $ newIORef pwd
lift $ bindKey '\t' (tabHandler pwdRef)
lift $ bindKey '\^L' ctlLHandler
commandLoop pwdRef) rootDir
return ()
tabHandler :: IORef FilePath -> Int -> Char -> IO Int
tabHandler pwdRef _ _ = do
pwd <- readIORef pwdRef
insertText pwd
return 0
...
commandLoop :: IORef FilePath -> MyState ()
commandLoop pwdRef = commandLoop'
where
commandLoop' = do
pwd <- get
lift $ writeIORef pwdRef pwd
maybeLine <- lift $ readline $ makePrompt $ dropTrailingPathSeparator pwd
case maybeLine of
Nothing -> return ()
Just "exit" -> return ()
Just line -> do
let tokens = words line
case tokens of
[] -> commandLoop'
("exit":_) -> return ()
_ -> do lift $ addHistory line
processLine tokens
commandLoop'
...
Is there any way in which I can do without IORef in tabHandler and commandLoop (written in red and bold, if you can see)?
Thanks,
Jinwoo
--
Jinwoo Lee
Always remember that you are unique. Just like everyone else.