3

Ugh... Struggling with haskell. Trying to implement Conway's GOL and create a random game board. Here is where I am at.

I have a function to randomize each square in an array, and a function to create an array of characters using the randomization function to represent my game board.

I am trying to now create a function: showBoard, which iterates through the array and concatenates each char to a string which I can print out in my main.

import System.Random
import Control.Monad
import Data.Array
import Data.List

randomBoard = do
    f1 <- randomIO :: IO Int
    if(f1 `mod` 2) == 0
        then return  '*'
        else return  ' '

boardArray :: IO (Array Int Char)
boardArray = listArray (0, 99) <$> replicateM 100 randomBoard


showBoard :: IO (Array Int Char) -> Int -> String -> String
showBoard arr i str = do
    if i > 0
       then showBoard arr (i-1) (str ++ (arr ! i))
       else return str

main :: IO ()
main = 
let board = showBoard boardArray 100 ""
    in
        do
            putStr board

I have spent an hour trying to tweak this out and keep getting type issues. I cant even get this board to print x.x please help.

1

1 Answer 1

3

A few problems:

  1. It's not possible to write a function that takes an IO of something and uses it to return something that isn't in IO. Change showBoard to take an Array Int Char without the IO wrapper, and remove do and return from it.
  2. Since your array is zero-based, change arr ! i to arr ! (i - 1).
  3. arr contains Chars, not Strings, so use [] instead of () around the indexing of it to make it into a String.
  4. Since we made showBoard take a value without IO, use <- in main to get at the inner value we need.

Here's the result of all of those changes:

import System.Random
import Control.Monad
import Data.Array
import Data.List

randomBoard = do
    f1 <- randomIO :: IO Int
    if(f1 `mod` 2) == 0
        then return  '*'
        else return  ' '

boardArray :: IO (Array Int Char)
boardArray = listArray (0, 99) <$> replicateM 100 randomBoard


showBoard :: Array Int Char -> Int -> String -> String
showBoard arr i str =
    if i > 0
       then showBoard arr (i-1) (str ++ [arr ! (i - 1)])
       else str

main :: IO ()
main = do
    randomArray <- boardArray
    let board = showBoard randomArray 100 ""
    putStr board

As an aside, the way showBoard is implemented, although it works, is particularly inefficient. You should avoid doing things that look like x ++ [y] recursively, as it's quadratically slow. Also, it looks like your function prints the elements starting at the end and going down to 0, rather than starting at 0 and going up to the end. Here's a new version of it that fixes both of those things at once:

showBoard :: Array Int Char -> Int -> String -> String
showBoard arr i str =
    if i > 0
       then showBoard arr (i-1) ((arr ! (i - 1)) : str)
       else str

Using : where possible is much more efficient than always using ++.

You can simplify even further by not having showBoard at all, and using elems (from Data.Array) instead:

main :: IO ()
main = do
    randomArray <- boardArray
    let board = elems randomArray
    putStr board
Sign up to request clarification or add additional context in comments.

1 Comment

Wow thanks! This is starting to make sense. Thanks for the advice on the efficiency as well. It works perfectly :)

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.