Reputation: 115
Now I improved the code a bit, cut something off it, etc.
Here is the source code:
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
So now, when I try try to compile it, I become this error:
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:
...
As I understand it, it trys to return a list of a list but it don't cause off:
mkDungeon :: Int -> Int -> Dungeon -> Dungeon
But if I write
else return $ dungeon
instead, I get this error:
main.hs:42:26:
Couldn't match type ‘[Tile]’ with ‘Tile’
Expected type: Dungeon
Actual type: [Dungeon]
In the expression: return $ dungeon
...
When I write it without $
, I get this:
main.hs:42:26:
Couldn't match type ‘[Tile]’ with ‘Tile’
Expected type: Tile
Actual type: Dungeon
In the expression: return dungeon
...
So how can I return it as type Dungeon?
Upvotes: 0
Views: 132
Reputation: 115
I solved It.
As you can see it in the code
I have solved it by making:
... $ dungeon ++ [Tile ...]
Thanks too all of you! It helped a lot :D.
Upvotes: 0
Reputation: 577
Since mkDungeon
has a type signature of mkDungeon :: Int -> Int -> Dungeon -> Dungeon
, and Dungeon
is the equivilent to [Tile]
, this function is in the list monad.
return
is a function defined for monads which lifts a value into monad you are using. return
for lists is defined as
return :: a -> [a]
return x = [x]
So since dungeon
has type Dungeon
, when you pass it to return
you get [dungeon]
. This is not what you want and does not match the type signature which is why you get the error.
You do not need to use return at all in this case, removing it should solve your problem. Just remember the return in Haskell is nothing like return in imperative languages; it is not used leave functions.
Upvotes: 0
Reputation: 62848
So another answer already explained that you need to use let x = ...
for normal values, and only use x <- ...
for monadic actions. So that's one of your problems.
You also don't need all those do
blocks in mkDungeon
. Rather than
then do
dungeon : Tile '#' True (x,y)
mkDungeon (x + 1) y
you want something like
then mkDungeon (x + 1) y (dungeon : Tile '#' True (x,y))
In other words, pass the new dungeon to a recursive call to mkDungeon
. But of course, this is the wrong way round: the new tile should be to the left of the (:)
operator, not the right.
then mkDungeon (x + 1) y (Tile '#' True (x,y) : dungeon)
The next problem is that you have
data Dungeon = Dungeon [Tile]
That means that if x
, y
and z
are Tile
values, then
Dungeon [x, y, z]
is a Dungeon
value, however
[x, y, z]
by itself is not. Your type signature for mkDungeon
claims it takes a Dungeon
and returns another Dungeon
, but in fact it seems to be trying to take a list of tiles and return another list of tiles.
There are two ways to fix this. One is to make Dungeon
a mere type alias rather than a whole new type:
type Dungeon = [Tile]
Now Dungeon
and [Tile]
are interchangeable, one merely being an alias to the other. Alternatively, you need to insert Dungeon
all over the place:
mkDungeon x y (Dungeon ts) = ...
...then mkDungeon (x + y) y (Dungeon (Tile '#' True (x,y) : ts))
...
Upvotes: 0
Reputation: 370415
main = do
let theDungeon :: Dungeon
theDungeon <- mkDungeon 0 0 []
writeFile "./test.log" $ show theDungeon
If we remove the syntactic sugar from this, we get:
main =
let
theDungeon :: Dungeon
in
mkDungeon 0 0 [] >>= \theDungeon ->
writeFile "./test.log" $ show theDungeon
What the error message is complaining about is the let
block contains a type signature for theDungeon
, but no actual definition. The next problem would be that mkDungeon 0 0 []
produces a value of type Dungeon
, which is not a monad, so you can't use >>=
(and by extension <-
) with it.
To define theDungeon
properly you need to use =
instead of <-
(<-
is for "extracting" values from monads and it's desugared using >>=
, =
is used for let
(and global) bindings) and indent it in such a way that it's still part of the let
block. So:
main = do
let theDungeon :: Dungeon
theDungeon = mkDungeon 0 0 []
writeFile "./test.log" $ show theDungeon
Or you can skip the type signature and just write let theDungeon = mkDungeon 0 0 []
.
Upvotes: 2