现在,我对代码进行了一些改进,将其裁剪掉,等等。
这是源代码:
import Prelude
{-- DEFINE THE TYPES --}
data Tile = Tile -- the tiles of the map
{char :: Char
,isBlocking :: Bool
,position :: (Int,Int)}
type Dungeon = [Tile] -- the dungeon
{-- THE MAIN FUNCTION --}
main :: IO ()
main = do
let theDungeon :: Dungeon
theDungeon = mkDungeon 0 0 []
writeFile "./test.log" $ show theDungeon
{-- DEFINE THE SIZE OF THE MAP --}
screenX = 80
screenY = 24
mapX = screenX
mapY = screenY - 4
{-- THE FUNCTIONS FOR THE DUNGEON --}
mkDungeon :: Int -> Int -> Dungeon -> Dungeon -- function for generating the dungeon
mkDungeon x y dungeon =
if x > mapX -- looks if the line isn't too long
then mkDungeon 0 (y + 1) dungeon -- it's too long, so make the next line
else if y == 0 -- if it at the top
then mkDungeon (x + 1) y $ dungeon ++ [Tile '#' True (x, y)}
else if y > 0 && y < mapY -- looks if the line is in the middle
then if x == 0 || x == mapX -- is it at the right or at the left
then mkDungeon (x + 1) y $ dungeon ++ [Tile '#' True (x, y)]
else mkDungeon (x + 1) y $ dungeon ++ Tile '.' False (x, y)]
else if y == mapX -- looks if it is at the bottom
then do mkDungeon (x + 1) y $ dungeon ++ [Tile '#' True (x, y)]
else return $ dungeon :: Dungeon
所以现在,当我尝试编译它时,我变成了这个错误:
main.hs:42:26:
Couldn't match type ‘[Tile]’ with ‘Tile’
Expected type: Dungeon
Actual type: [Dungeon]
In the expression: return $ dungeon :: Dungeon
In the expression:
...
据我了解,它尝试返回列表的列表,但不会导致关闭:
mkDungeon :: Int -> Int -> Dungeon -> Dungeon
但是如果我写
else return $ dungeon
相反,我收到此错误:
main.hs:42:26:
Couldn't match type ‘[Tile]’ with ‘Tile’
Expected type: Dungeon
Actual type: [Dungeon]
In the expression: return $ dungeon
...
当我不使用
$
编写它时,我得到了:main.hs:42:26:
Couldn't match type ‘[Tile]’ with ‘Tile’
Expected type: Tile
Actual type: Dungeon
In the expression: return dungeon
...
那么,如何将其作为Dungeon类型返回?
最佳答案
因此,另一个答案已经说明,您需要将let x = ...
用作常规值,而仅将x <- ...
用作单子(monad) Action 。这是您的问题之一。
您也不需要do
中的所有这些mkDungeon
块。而不是
then do
dungeon : Tile '#' True (x,y)
mkDungeon (x + 1) y
你想要类似的东西
then mkDungeon (x + 1) y (dungeon : Tile '#' True (x,y))
换句话说,将新的地牢传递给
mkDungeon
的递归调用。但是,当然,这是错误的方法:新的图块应位于(:)
运算符的左侧,而不是右侧。then mkDungeon (x + 1) y (Tile '#' True (x,y) : dungeon)
下一个问题是你有
data Dungeon = Dungeon [Tile]
这意味着如果
x
,y
和z
是Tile
值,则Dungeon [x, y, z]
是
Dungeon
值,但是[x, y, z]
本身不是。您的
mkDungeon
类型签名声称需要一个Dungeon
并返回另一个Dungeon
,但实际上,它似乎正在尝试获取一个 slice 列表并返回另一个 slice 列表。有两种方法可以解决此问题。一种是使
Dungeon
成为纯类型别名,而不是全新的类型:type Dungeon = [Tile]
现在
Dungeon
和[Tile]
是可互换的,一个仅仅是另一个的别名。或者,您需要在各处插入Dungeon
:mkDungeon x y (Dungeon ts) = ...
...then mkDungeon (x + y) y (Dungeon (Tile '#' True (x,y) : ts))
...