Reputation: 59
I am beginner in Haskell and I struggle with IO operations. I should get IO String from user until user send "." (point) character. I will use these inputs to transform Custom Data Type, naming Card, by parsing the String. And then I will add the Card to the list. When user types the ".", I will send whole Card List. Haskell code is below:
readCards :: IO [Card]
readCards = return (returnCardList [])
where
returnCardList :: [Card] -> [Card]
returnCardList acc = do line <- getLine
if line == "."
then acc
else returnCardList ((convertCard (line !! 0) (line !! 1)):acc)
convertCard
is a function which takes two char
and return Card
. Also acc
stand for accumulator for tail recursion function (It is not necessary to implement with tail recursion, I just chose it).
For example returnCardList 'h' 'q'
gives Card {suit=Hearts, rank=Queen}
However above code partition gives an error:
Couldn't match type `IO' with `[]'
Expected type: [String]
Actual type: IO String
However below code (with dummy Card List) run properly:
readCards :: IO [Card]
readCards = return [Card {suit=Clubs, rank=King}, Card {suit=Clubs, rank=Ace}, Card {suit=Clubs, rank=Jack}]
I read a lot of things but I couldn't solve it. I am really wonder what I miss.
Upvotes: 0
Views: 884
Reputation: 116174
This code
readCards :: IO [Card]
readCards = return (returnCardList [])
is stating that readCards
is an IO computation that does not actually do IO. Indeed return something
implies that no IO is being performed, and that something
is a pure value of type [Card]
.
This is not what you want. You need something like
readCards :: IO [Card]
readCards = returnCardList []
Consequently, the IO must be done by returnCardList
, which must now have the type
returnCardList :: [Card] -> IO [Card]
-- ^^ we do perform IO here!
Your own implementation should work, roughly
returnCardList acc = do
line <- getLine
if line == "."
then return acc
-- ^^^^^^ turn the plain value into an IO computation
else returnCardList ((convertCard (line !! 0) (line !! 1)):acc)
This can be rewritten as follows:
returnCardList acc = do
line <- getLine
case line of
"." -> return acc
(c1:c2:_) -> returnCardList (convertCard c1 c2 : acc)
_ -> ... -- you should handle here the other cases (length < 2)
Note that you can also do without an acc
parameter:
returnCardList = do
line <- getLine
case line of
"." -> return []
(c1:c2:_) -> (convertCard c1 c2 :) <$> returnCardList
_ -> ... -- you should handle here the other cases (length < 2)
Upvotes: 1