2
\$\begingroup\$

I am currently learning Haskell and as an exercise, I am building a simple tic-tac-toe program. I start with

import Data.Vector

data Cell = Empty | X | O
type Board = Vector Cell

and then, to render the board:

render :: Board -> IO ()
render b = do
    renderSep
    renderRow 0 b
    renderSep
    renderRow 1 b
    renderSep
    renderRow 2 b
    renderSep
  where
    renderSep :: IO ()
    renderSep = putStrLn "+---+---+---+"
    renderRow :: Int -> Board -> IO ()
    renderRow r b = do
        putStr "| " >> putStr (cellRepr $ getCell r 0 b)
        putStr " | " >> putStr (cellRepr $ getCell r 1 b)
        putStr " | " >> putStr (cellRepr $ getCell r 2 b)
        putStrLn " |"

How could I abstract my implementation so that there's less repetition? Especially in the main body of the render function. I thought of using sequence together with the list fmap (\x -> renderRow x b >> renderSep) [0, 1, 2]. However, in this case I get a value of type IO [()] and not IO ().

\$\endgroup\$
6
  • \$\begingroup\$ Have you tried writing functions? \$\endgroup\$
    – Mast
    Commented Sep 18, 2020 at 9:11
  • \$\begingroup\$ I'm sorry, I don't see what you mean. I wrote functions, yes. \$\endgroup\$ Commented Sep 18, 2020 at 9:13
  • 1
    \$\begingroup\$ To avoid the repetition. \$\endgroup\$
    – Mast
    Commented Sep 18, 2020 at 9:16
  • \$\begingroup\$ I don't know haskell, but if you can write loops in the language that should take care of some of the code repetition. \$\endgroup\$
    – pacmaninbw
    Commented Sep 18, 2020 at 23:31
  • 1
    \$\begingroup\$ A possible improvement is to use forM_ – notice the underscore, which is a convention and means that we discard the results. Using this function you can replace the repetitive part with forM_ [0..2] $ \i -> renderRow i b >> renderSep. \$\endgroup\$ Commented Sep 27, 2020 at 7:22

1 Answer 1

1
\$\begingroup\$

I think a simple way to address the problem is by building the board first then printing it:

empty_row :: String
empty_row = "+---+---+---+"

board_repr :: type of b -> String
board_repr b = empty_row + concat ( map (\x -> (build_row x b) + empty_row ) [0, 1, 2] )

main = print (board_repr b)

Take this as pseudo-code pointing in an interesting direction by separating the concerns of building a representation and printing it.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.