0

I am trying to use UI.NCurses

https://john-millikin.com/software/haskell-ncurses/reference/haskell-ncurses/latest/

for some simple path finding lessons The issue is I have a random Int which of course returns an IO Int which then means I have an IO TerrianType which then leads to an array of IO TerrianType

the issue is I need to resolve these in main so they can be printed to the screen using drawString. I am including the code below:

module Main where
  2   import UI.NCurses
  3   import Control.Monad
  4   import Control.Monad.IO.Class
  5   import System.Random
  6 
  7   -- Tutorials
  8   -- working on several path findng algorithims
  9   -- http://www.redblobgames.com/pathfinding/a-star/introduction.html
 10 
 11   -- | The 'Compass' data type provides breadcrumbs from the goal to the start. 
 12   data Compass = N | S | E | W deriving (Show, Eq)
 13 
 14   -- | 'Cartogram' is a structure of compass directions that mirrors the terrian.
 15   type Cartogram = [Compass]
 16 
 17   -- | 'TerrianType' determines how hard a cell is to traverse.
 18   data TerrianType = Sand | Forest | Goal deriving (Show, Eq)
 19 
 20   -- | 'Terrian' is a collection of TerrianTypes with a single goal.
 21   type Terrian = [IO TerrianType]
 22 
 23   -- | 'roll' gets a random int from 1 to the parameter
 24   roll :: Int -> IO Int
 25   roll m
 26     | m <= 0 = getStdRandom (randomR (1,1))
 27     | m > 0 = getStdRandom (randomR (1,m)) 
 28 
 29   -- | 'getRandomTerrian' gets a random TerrianType 
 30   getRandomTerrian :: IO TerrianType
 31   getRandomTerrian = do
 32     r <- roll 3
 33     case r of
 34       1 -> return Forest
 35       2 -> return Sand
 36       3 -> return Goal
 37       _ -> return Sand
 38 
 39   -- | 'constructTerrian' constructs a Terrian array of random TerrianTypes
 40   constructTerrian :: Int -> Int -> Terrian
 41   constructTerrian n1 n2 = take (n1 * n2) $ repeat getRandomTerrian
 42 
 43   drawShow a = (drawString . show) a
 44  
 45   --showString :: t -> String
 46   --showString t = show t
 47 
 48   main :: IO ()
 49   main = do
 50     runCurses $ do
 51       setEcho False
 52       w <- defaultWindow
 53       updateWindow w $ do
 54         moveCursor 1 1
 55         mapM drawShow (constructTerrian 5 5)
 56       render
 57       waitFor w (\ev -> ev == EventCharacter 'q' || ev == EventCharacter 'Q')58 
 59   waitFor :: Window -> (Event -> Bool) -> Curses ()
 60   waitFor w p = loop where
 61     loop = do
 62       ev <- getEvent w Nothing
 63       case ev of
 64         Nothing -> loop
 65         Just ev' -> if p ev' then return () else loop

 • No instance for (Show (IO TerrianType))
        arising from a use of ‘drawShow’
 • In the first argument of ‘mapM’, namely ‘drawShow’
      In a stmt of a 'do' block: mapM drawShow (constructTerrian 5 5)
      In the second argument of ‘($)’, namely
        ‘do { moveCursor 1 1;
              mapM drawShow (constructTerrian 5 5) }’
duplode
  • 33,731
  • 7
  • 79
  • 150
liminal18
  • 563
  • 7
  • 21

1 Answers1

1

I think you are confusing [IO TerrianType] and IO [TerrianType].

In your code you produce a [IO TerrianType], which is a list of IO actions. When you mapM over that, you have to run the actions if you want to access their TerrianType and print it.

So, you probably need something like

drawShow :: (IO TerrianType) -> IO ()
drawShow a = a >>= drawString . show

However, I do wonder if [IO TerrianType] is the right thing to begin with. Instead of using

constructTerrian :: Int -> Int -> [IO TerrianType]

as you are doing now, you probably should move to

constructTerrian :: Int -> Int -> IO [TerrianType]

and change the code accordingly. The first code does not compute the random values, but only returns a list of IO actions which will roll the random values. Maybe you instead want to roll them now, and produce a list of values, as the second type implies.

chi
  • 111,837
  • 3
  • 133
  • 218
  • hey thaks I will give that a shot. not sure if I can do IO [TerrianType] becasue the IO comes from the random Int but will try – liminal18 May 06 '17 at 09:51
  • Yeah: Couldn't match expected type ‘IO Terrian’ with actual type ‘[IO TerrianType]’ • In the expression: take (n1 * n2) $ repeat getRandomTerrian – liminal18 May 06 '17 at 09:54
  • 1
    @liminal18 Note that we have `sequence :: [IO a] -> IO [a]` which can convert one into the other. Probably there are better ways to do it, but this is a basic way, at least. – chi May 06 '17 at 11:53
  • Yeah I ended up using replicateM on the random function to compile a list of int then constructing my TerrainType list. Is working thanks – liminal18 May 06 '17 at 11:54