Reputation: 337
I am new to Haskell, and I try to understand how to do IO correctly.
The following works ok:
main = do
action <- cmdParser
putStrLn "Username to add to the password manager:"
username <- getLine
case action of
Add -> persist entry
where
entry = Entry username "somepassword"
Whereas the following results in compilation error:
main = do
action <- cmdParser
case action of
Add -> persist entry
where
entry = Entry promptUsername "somepassword"
promptUsername = do
putStrLn "Username to add to the password manager:"
username <- getLine
The error is here:
Couldn't match expected type `IO b0' with actual type `[Char]'
Expected type: IO b0
Actual type: String
In the expression: username
[...]
What is going on here? Why the first version works, while the second one does not?
I know that in Stack Overflow there are a few similar questions like this, but none of them seemed to explain this problem to me.
Upvotes: 6
Views: 21844
Reputation: 8199
Here's another variant.
main = do
action <- cmdParser
case action of
Add -> do username <- promptUsername
let entry = Entry username "somepassword"
persist entry
promptUsername :: IO String
promptUsername = do
putStrLn "Username to add to the password manager:"
getLine
-- fake definitions to make things compile
persist :: Entry -> IO ()
persist = print
cmdParser :: IO Add
cmdParser = fmap (const Add) getLine
data Add = Add deriving Show
data Entry = Entry String String deriving Show
The problem is just that promptUsername
is an action not a String. The action 'returns a String', so it has type IO String
, but it is itself nothing like a String. Since Entry x y
requires a String
in the x position, something in the shape of an action could no more fit there than a number or boolean could. So in defining your complex action, main
, you must 'extract' the string that will result from the simpler action promptUsername
in any case of execution, and give the String
as the first argument the entry. Then you do the persist
action on the resulting Entry
Upvotes: 0
Reputation: 6441
username
is a String
, but promptUsername
is an IO String
. You need to do something like:
username <- promptUsername
let entry = Entry username "somepassword"
persist entry
Upvotes: 10