im really new to haskell and i'm trying to implement a simple connect4 game, when I try to get the player to input a new move I want to prompt him to do so. This is the relevant code I have:
advanceHuman :: Board -> Board
advanceHuman b = do
let column = query
if (snd((possibleMoves b)!!(column-1)) == cha)
then updateBoard b p1 column
else advanceHuman b
query :: Int
query = do {
print ("escoge una columna vacia") ; -- choose empty column
input <- getLine ;
return (read input) }
as you can see I try to prompt the player, get his answer and pass it to other functions (it is assumed the player will be cooperative and input a valid number). However, this is the error message I get when I try to compile
* Couldn't match expected type `Int' with actual type `IO b0'
* In a stmt of a 'do' block: print ("escoge una columna vacia")
In the expression:
do print ("escoge una columna vacia")
input <- getLine
return (read input)
In an equation for `query':
query
= do print ("escoge una columna vacia")
input <- getLine
return (read input)
|
47 | print ("escoge una columna vacia") ;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
To my understanging, I should be able to print a line in a do block regardless of what that function is outputing right? Whats the issue, have I misunderstood how "do" works?
UPDT
as requested, these are the other functions involved
possibleMoves:: Board -> Board
possibleMoves b = take sx b
updateBoard:: Board -> String -> Int -> Board
updateBoard b pl col = b
Updateboard has not been implemented yet so it just has some dummy code to appease the compiler
p1 cha and sx are global constants declared beforehand
Basically I chop off the top of my board to check which columns are full ('_' = empty), check the top of the column the player specifies with "query" to see if its a legal move; if not, the process starts again.
The theory of monads is very interesting and it is well worth your while to dive into it and understand it all deeply. But here's a mostly wrong answer to help you get started coding without worrying about all that.
There are two kinds of things, values and actions. Actions have types wrapped in
IO, likeIO Int,IO String,IO (Maybe [Bool]). Actions are the way you do I/O. They do some I/O, and after they are done, they return a value of the type they wrap.Actions are constructed with
do, and usually the last line hasreturn <value>(or is another action, in which case it uses the return value of that one). So yourqueryis an action:The way you use actions is by binding them using the
<-, which you have already done withgetLine. This can only be done in adoblock. So when you want to usequeryinadvanceHuman, you need to bind it:The name (or pattern) on the left of the binding becomes a value of type whatever was wrapped in
IO-- in this caseInt.However, I said that
doconstructs actions. This means thatadvanceHumanneeds to return an action type:The only things that can be lines in a do block are actions, either bound to values or not, and
return <value>(which, as it turns out, is also an action).You must bind actions before you use their values. E.g. if you have
Then you can't say
getX + getYto get their sum. You have to saydo { x <- getX; y <- getY; return (x + y) }(orliftA2 (+) getX getY, but let's not get ahead of ourselves).If you want to bind a name to a value instead of an action, you use
letinstead. So inadvanceHumanyou usedletwhen you should have used<-becausequeryis an action.Hope this helps.