Haskell newbie here :) . I wan´t to read iteratively an element from IO and, in case is present, delete the element from the list . In other case, repeat the reading till the element entered is in the list. I have the following code :
import Data.List (delete)
main = do
let initialDieRoll = [23,45,98,34]
strength <- askStrength
let dieRollWithoutStrength = removeStrengthFromDieRollLoop strength initialDieRoll
print dieRollWithoutStrength
removeStrengthFromDieRollLoop :: Int -> [Int] -> [Int]
removeStrengthFromDieRollLoop = removeStrengthFromDieRoll
removeStrengthFromDieRoll :: Int -> [Int] -> [Int]
removeStrengthFromDieRoll strength dieRoll = do
if strength `elem` dieRoll then
delete strength dieRoll
else do
"Please, choose an element from the initial die roll"
newStrength <- askStrength
removeStrengthFromDieRollLoop askStrength dieRoll
askStrength :: IO Int
askStrength = do
putStr "Strength : "
readLn::IO Int
But , when I request the new strength, I'm getting the following error :
Couldn't match type ‘IO’ with ‘[]’
Expected: [Int]
Actual: IO Int
In a stmt of a 'do' block: newStrength <- askStrength
In the expression:
do "Please, choose an element from the initial die roll"
newStrength <- askStrength
removeStrengthFromDieRollLoop askStrength dieRoll
In a stmt of a 'do' block:
if strength `elem` dieRoll then
delete st
What is the best way to proceed ? How can I fix the error, and which is the best way to request for the value looping each time if the value is not inside the initial list ? . Thanks .
Here's some code that compiles. (I have not run it, though)
removeStrengthFromDieRoll :: Int -> [Int] -> IO [Int]
removeStrengthFromDieRoll strength dieRoll = do
if strength `elem` dieRoll then
return (delete strength dieRoll)
else do
putStrLn "Please, choose an element from the initial die roll"
newStrength <- askStrength
removeStrengthFromDieRoll newStrength dieRoll
askStrength :: IO Int
askStrength = do
putStr "Strength : "
-- You might need hFlush stdout here, I'm not sure.
readLn :: IO Int
Some key aspects:
All functions that do IO, either directly or indirectly, must have a type of the form ... -> IO something
. So, askStrength
must have an IO type since it calls putStr
. Hence, removeStrengthFromDieRoll
must also have an IO type. Hence, if you use removeStrengthFromDieRoll
in another function, that must still have an IO type, etc. "IO is viral" is a common way to state this.
If you need to print a string, you need something like putStrLn
. You can't simply use a string "Please, ...."
.
When you need to return inside IO, but you only have a non-IO value, like the list delete strength dieRoll
above, you need to bring that inside IO using the return
function (or, equivalently, pure
). Note that return
is not the same as in C,C++,Java,... but in Haskell is only used to convert someType
into IO someType
, so that "pure" values can be returned ina function that has an IO
result type.
Finally, IO can be tricky at first to grasp from beginners. We all have been there. I'd suggest to following an IO monad tutorial, if you have not yet done so: there should be plenty of them around the 'net.