当我尝试 return 列表时出错
errors when I try to return a list
现在我改进了代码,删掉了一些东西,等等
这是源代码:
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:
...
据我了解,它会尝试 return 一个列表的列表,但不会导致关闭:
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
...
那么我怎样才能return它是地牢类型呢?
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
,您需要使用 =
而不是 <-
(<-
用于来自 monad 的 "extracting" 值,它使用 >>=
,=
用于 let
(和全局)绑定)并缩进它,使其仍然是 let
块的一部分。所以:
main = do
let theDungeon :: Dungeon
theDungeon = mkDungeon 0 0 []
writeFile "./test.log" $ show theDungeon
或者你可以跳过类型签名,只写 let theDungeon = mkDungeon 0 0 []
.
所以另一个答案已经解释了你需要使用 let x = ...
来表示正常值,并且只使用 x <- ...
来表示单子动作。所以这是你的问题之一。
您也不需要 mkDungeon
中的所有那些 do
块。而不是
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
和 return 另一个 Dungeon
,但实际上它似乎试图获取一个图块列表和 return 另一个瓷砖列表。
有两种方法可以解决这个问题。一种是使 Dungeon
成为一个类型别名而不是一个全新的类型:
type Dungeon = [Tile]
现在 Dungeon
和 [Tile]
可以互换,一个只是另一个的别名。或者,您需要在整个地方插入 Dungeon
:
mkDungeon x y (Dungeon ts) = ...
...then mkDungeon (x + y) y (Dungeon (Tile '#' True (x,y) : ts))
...
因为 mkDungeon
的类型签名是 mkDungeon :: Int -> Int -> Dungeon -> Dungeon
,并且 Dungeon
等价于 [Tile]
,所以这个函数在列表 monad 中。
return
是为 monad 定义的函数,它将一个值提升到您正在使用的 monad 中。 return
对于列表定义为
return :: a -> [a]
return x = [x]
因此,由于 dungeon
的类型为 Dungeon
,当您将其传递给 return
时,您会得到 [dungeon]
。这不是您想要的,并且与类型签名不匹配,这就是您收到错误的原因。
在这种情况下您根本不需要使用 return,删除它应该可以解决您的问题。请记住 Haskell 中的 return 与命令式语言中的 return 完全不同;它没有使用休假功能。
我解决了。
正如您在 code
中看到的那样
我已经通过制作解决了它:
... $ dungeon ++ [Tile ...]
也谢谢大家!帮了大忙 :D.
现在我改进了代码,删掉了一些东西,等等
这是源代码:
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:
...
据我了解,它会尝试 return 一个列表的列表,但不会导致关闭:
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
...
那么我怎样才能return它是地牢类型呢?
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
,您需要使用 =
而不是 <-
(<-
用于来自 monad 的 "extracting" 值,它使用 >>=
,=
用于 let
(和全局)绑定)并缩进它,使其仍然是 let
块的一部分。所以:
main = do
let theDungeon :: Dungeon
theDungeon = mkDungeon 0 0 []
writeFile "./test.log" $ show theDungeon
或者你可以跳过类型签名,只写 let theDungeon = mkDungeon 0 0 []
.
所以另一个答案已经解释了你需要使用 let x = ...
来表示正常值,并且只使用 x <- ...
来表示单子动作。所以这是你的问题之一。
您也不需要 mkDungeon
中的所有那些 do
块。而不是
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
和 return 另一个 Dungeon
,但实际上它似乎试图获取一个图块列表和 return 另一个瓷砖列表。
有两种方法可以解决这个问题。一种是使 Dungeon
成为一个类型别名而不是一个全新的类型:
type Dungeon = [Tile]
现在 Dungeon
和 [Tile]
可以互换,一个只是另一个的别名。或者,您需要在整个地方插入 Dungeon
:
mkDungeon x y (Dungeon ts) = ...
...then mkDungeon (x + y) y (Dungeon (Tile '#' True (x,y) : ts))
...
因为 mkDungeon
的类型签名是 mkDungeon :: Int -> Int -> Dungeon -> Dungeon
,并且 Dungeon
等价于 [Tile]
,所以这个函数在列表 monad 中。
return
是为 monad 定义的函数,它将一个值提升到您正在使用的 monad 中。 return
对于列表定义为
return :: a -> [a]
return x = [x]
因此,由于 dungeon
的类型为 Dungeon
,当您将其传递给 return
时,您会得到 [dungeon]
。这不是您想要的,并且与类型签名不匹配,这就是您收到错误的原因。
在这种情况下您根本不需要使用 return,删除它应该可以解决您的问题。请记住 Haskell 中的 return 与命令式语言中的 return 完全不同;它没有使用休假功能。
我解决了。
正如您在 code
中看到的那样
我已经通过制作解决了它:
... $ dungeon ++ [Tile ...]
也谢谢大家!帮了大忙 :D.