Tic Tac Toe game in haskell follow up
With the new board representation, the brute-force pattern matching is gone, which is good.  Still, I personally prefer the 1–9 numbering for simpler user interface — perhaps a translation function could be implemented.  Note that you forgot to adjust the introductory message for the new coordinate system.

Instead of the showTile function, you should use the standard Show typeclass:

instance Show Tile where
    show EmptyTile = " "
    show X         = "X"
    show O         = "O"


In showBoard you used both let … in and where.  Pick one or the other (I prefer where).

As mentioned in my previous answer, all of your functions that accept a Board should place the board parameter last, since the board is what they all operate on.  With tileWins :: Tile -&gt; Board, for example, you can define p1wins = tileWins X using the point-free style.

data Player = Player1 | Player2 isn't doing anything useful for you.  You are hard-coding the Player1 ↔︎ X and the Player2 ↔︎ O correspondence all over the place, in main, p1wins, p2wins, and compMove.

With this second version, then, I would say that the greatest improvement can be made in handling the two players.  Here is my suggestion:

humanTurn :: Tile -&gt; Board -&gt; IO Board
humanTurn t b = do
    putStrLn $ showBoard b
    move
    where
        move = do
            row &lt;- prompt "Row: "
            col &lt;- prompt "Col: "
            let newboard = put b t (read row) (read col)
            case newboard of
                Nothing -&gt; do
                            putStrLn "Invalid move."
                            move
                Just b' -&gt; return b'

computerTurn :: Tile -&gt; Board -&gt; IO Board
computerTurn t b = do
    (row, col) &lt;- getRandomEmpty b 
    let (Just b') = put b t row col
    return b'

main :: IO ()
main = do
    putStrLn "This is the classic tic tac toe game."
    putStrLn "Enter the coordinates for each move according to this scheme:"
    putStrLn showTileNumbers
    play player1 player2 emptyBoard
    where
        player1 = (X, humanTurn, "You win!")
        player2 = (O, computerTurn, "You lose.")
        play p@(tile, turn, winMsg) p' b = do
            b' &lt;- turn tile b
            if tileWins tile b' then do
                putStrLn $ showBoard b'
                putStrLn winMsg
            else if checkFull b' then do
                putStrLn $ showBoard b'
                putStrLn "Tie."
            else
                play p' p b'


This turns main into a leaner state machine.  As evidence of the superiority of this design, observe that you can make a human-vs.-human game simply by changing two lines to…

       player1 = (X, humanTurn, "X wins.")
       player2 = (O, humanTurn, "O wins.")