将 IO 与 Ncurses 一起使用

Using IO with Ncurses

我正在尝试使用 UI.NCurses

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

一些简单的寻路课程 问题是我有一个随机 Int,当然 returns 一个 IO Int 这意味着我有一个 IO TerrianType 然后导致一个 IO TerrianType

数组

问题是我需要在 main 中解决这些问题,以便可以使用 drawString 将它们打印到屏幕上。我包括以下代码:

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) }’

我认为你混淆了 [IO TerrianType]IO [TerrianType]

在您的代码中,您生成了一个 [IO TerrianType],这是一个 IO 操作列表。当你 mapM 超过它时,如果你想访问他们的 TerrianType 并打印它,你必须 运行 操作。

所以,您可能需要像

这样的东西
drawShow :: (IO TerrianType) -> IO ()
drawShow a = a >>= drawString . show

但是,我想知道 [IO TerrianType] 是否是正确的开始。而不是使用

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

就像你现在做的那样,你可能应该搬到

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

并相应地更改代码。第一个代码不计算随机值,而只计算 returns 将滚动随机值的 IO 操作列表。也许您现在想滚动它们,并生成一个值列表,正如第二种类型所暗示的那样。