The types in TicTacToe now look like this.
-- There are two players, X and O. These are not Chars. They are objects.
-- They are similar to True and False.
data Player = X | O deriving (Eq, Show)
-- The type Outcome refers to the outcome of the game.
-- There is either a Winner, which will be a player, or the game is a Draw.
data Outcome = Winner Player | Draw
instance Show Outcome where
show (Winner p) = show p ++ " wins."
show Draw = "Drawn game."
-- The type Mark refers to the contents of the game board.
-- A Board cell can have a Player's Mark, or it can be empty.
data Mark = Mark Player | Empty deriving Eq
instance Show Mark where
show (Mark p) = show p
show Empty = " "
-- A Row is three Marks.
type Row = [Mark] -- [Mark, Mark, Mark]
-- The Board is three Rows.
type Board = [Row] -- [[Mark, Mark, Mark],
-- [Mark, Mark, Mark],
-- [Mark, Mark, Mark]]
Although this makes the code somewhat more wordy, it also makes the types more descriptive. You will find that most professional software development organizations prefer clearer, if a bit longer, code to shorter but more obscure code.