现在我改进了代码,削减了一些东西,等等 这是源代码:
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类型返回?
答案 0 :(得分:2)
main = do
let theDungeon :: Dungeon
theDungeon <- mkDungeon 0 0 []
writeFile "./test.log" $ show theDungeon
如果我们从中删除语法糖,我们得到:
main =
let
theDungeon :: Dungeon
in
mkDungeon 0 0 [] >>= \theDungeon ->
writeFile "./test.log" $ show theDungeon
错误消息抱怨的是let
块包含theDungeon
的类型签名,但没有实际定义。下一个问题是mkDungeon 0 0 []
会生成Dungeon
类型的值,而不是monad,因此您无法使用>>=
(并且可以使用<-
用它。
要正确定义theDungeon
,您需要使用=
代替<-
(<-
用于&#34;从monad中提取&#34;值&#39}使用>>=
进行desugared,=
用于let
(和全局)绑定)并将其缩进,使其仍然是let
的一部分阻止。所以:
main = do
let theDungeon :: Dungeon
theDungeon = mkDungeon 0 0 []
writeFile "./test.log" $ show theDungeon
或者您可以跳过类型签名,只需编写let theDungeon = mkDungeon 0 0 []
。
答案 1 :(得分:0)
所以另一个答案已经解释过你需要使用let x = ...
作为正常值,并且只使用x <- ...
进行monadic动作。这就是你的一个问题。
您也不需要do
中的所有mkDungeon
块。而不是
then do
dungeon : Tile '#' True (x,y)
mkDungeon (x + 1) y
你想要像
这样的东西then mkDungeon (x + 1) y (dungeon : Tile '#' True (x,y))
换句话说,传递新地牢到递归调用mkDungeon
。但当然,这是错误的方式:新的磁贴应该是(:)
运算符的 left ,而不是右边。
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
,但实际上它似乎正在尝试获取切片列表并返回另一个切片列表。
有两种方法可以解决这个问题。一种是使Dungeon
仅仅是一种类型别名而不是一种全新的类型:
type Dungeon = [Tile]
现在Dungeon
和[Tile]
可以互换,只是另一个的别名。或者,您需要在所有地方插入Dungeon
:
mkDungeon x y (Dungeon ts) = ...
...then mkDungeon (x + y) y (Dungeon (Tile '#' True (x,y) : ts))
...
答案 2 :(得分:0)
由于mkDungeon
的类型签名为mkDungeon :: Int -> Int -> Dungeon -> Dungeon
,而Dungeon
与[Tile]
相同,因此此函数位于列表monad中。
return
是为monad定义的函数,它将值提升为您正在使用的monad。列表的return
定义为
return :: a -> [a]
return x = [x]
因为dungeon
的类型为Dungeon
,所以当您将其传递给return
时,您会获得[dungeon]
。这不是您想要的,并且与类型签名不匹配,这就是您收到错误的原因。
在这种情况下你根本不需要使用返回,删除它应该可以解决你的问题。请记住,Haskell中的返回与命令式语言中的返回完全不同;它不用于休假功能。
答案 3 :(得分:0)