I wrote a program in Haskell that builds a guitar tab as a txt file in the current directory. It gets a String of chords from the user, and then builds the proper output and writes it line by line to a file.
I wasn't able to use the backspace key on my input when I was using getLine, because it would print a bunch of gibberish to the screen.
I'm trying to use haskeline to fix this, and I commented out the bulk of my main method in the meantime so that each change requires less editing (every command I commented out in 'main' is of the same type as the single command I kept, so if I can get this simplified version to work, the whole thing should work). Basically, I need to be able to get the input from the user using haskeline, but then I also need to run some "side effects" commands in my "do" block after I do that.
I'm new to Haskell and I don't fully understand what is and is not allowed or why. Here's the simplified version of my program:
import Data.List
import System.Console.Haskeline
main = runInputT defaultSettings loop
where
loop :: InputT IO ()
loop = do
name <- getInputLine "Enter name of song: "
case name of
Nothing -> return ()
Just songName -> return ()
chords <- getInputLine "Enter chords to be tabified "
case chords of
Nothing -> do outputStrLn $ "No chords entered. Exiting."
Just chords -> do
writeFile "./test.txt" "did it work?"
return ()
I got all of this syntax straight from a Haskeline tutorial. I tried running it without making any changes first and it worked, so I know that it's all correct -except- for the last 3 lines that I edited, where I have the "do" block and am trying to call "writeFile" before "return()".
I know that the type of "loop" has to be InputT IO () in order to use getInputLine (the haskeline version of getLine), but I don't know how to accomplish "side effects" like writing to a file at the same time.
When I try to load my project in ghci, I get the following error:
error:
-Couldn't match type 'IO' with 'InputT IO'
Expected type: InputT IO ()
Actual type: IO ()
- In a stmt of a 'd' block: writeFile "./test.txt" "did it work?"
In the expression:
do { writeFile "./test.txt" "did it work?";
return () }
In a case alternative:
Just chords
-> do { writeFile "./test.txt" "did it work?";
return () }
Failed, modules loaded: none.
Since InputT IO
is an instance of MonadIO
, you can run any IO action by lifting it to a InputT IO
action, using
liftIO :: IO a -> InputT IO a
Indeed, this is the standard way to "run IO" in moands that support IO but aren't IO
.