Mandorman
Mandorman

Reputation: 21

How to deal with a list of 'Maybe [values]' in Haskell?

I tryied to adapt some exercises of the excelent book "Land of Lisp" of Conrad Barski in order to learn Haskell. The idea is to make a simple text game engine.

Concretely I tried :

type Clau = String
type Descripcio = String
type Valors = [String]

-- NOTE : Ideas of types http://learnyouahaskell.com/making-our-own-types-and-typeclasses
data Lloc = Lloc String String String deriving (Show) 
llocSituacio :: Lloc -> String  
llocSituacio (Lloc situacio _ _ ) = situacio  
llocDireccio :: Lloc -> String
llocDireccio (Lloc _ direccio _) = direccio
llocPas :: Lloc -> String
llocPas ( Lloc _ _ pas) = pas

nodes :: [(Clau,Descripcio)]
nodes = [("living-room","you are in the living-room. a wizard is snoring loudly on the couch.")
           ,("garden","you are in a beautiful garden. there is a well in front of you.")
           , ("attic", "you are in the attic. there is a giant welding torch in the corner.")]

edges :: [([Char], [Lloc])]
edges = [ ("living-room", [(Lloc "garden"  "west" "door"), ( Lloc "attic" "upstairs" "ladder") ])
        , ("attic", [(Lloc "living-room"  "east"  "door")])
        , ("garden", [(Lloc "living-room" "east"  "door")])]

describePath :: Lloc -> String  
describePath  e = "There is " ++ llocPas e ++ " going " ++ llocDireccio e ++ " from here." 

At first, it seems that works well. For example:

*TextGame> describePath (Lloc "living-room"  "east"  "door")
"There is door going east from here."

But when I try to apply the function to the list I got this error:

situacio = "garden"
map (describePath) (lookup situacio edges)



<interactive>:2:22: error:
    • Couldn't match expected **type ‘[Maybe Lloc]’**
                  with actual **type ‘Maybe [Lloc]’**
    • In the second argument of ‘map’, namely ‘(lookup situacio edges)’
      In the expression: map (describePath) (lookup situacio edges)
      In an equation for ‘it’:
          it = map (describePath) (lookup situacio edges)

The error is clear, but I do not manage to solve it. I want to parse the list of Maybe's values and print the path with the function describePath that works well:

Any ideas? Also, if somebody wants to share alternatives or feel that this code could be more in Haskell style, please feel free to talk about it.

Upvotes: 1

Views: 535

Answers (2)

Mandorman
Mandorman

Reputation: 21

Thanks a lot chi, it works perfectly. I just made a new function:

describePaths situacio edges = case lookup situacio edges of
    Nothing -> []
    Just locs -> map describePath locs

.. and works pretty well:

*TextGame> situacio = "living-room"
*TextGame> describePaths situacio edges
["There is door going west from here.","There is ladder going upstairs from here."]

But I see that I do not fully understand the <$> operator. I follow the comments of : What does <$> mean in Haskell?

So I follow the suggestion : https://hoogle.haskell.org/?hoogle=%3C$%3E

This is call a Functor:

(<$>) :: Functor f => (a->b) -> f a -> f b

That actually is exactly the same as fmap:

fmap :: Functor f => (a -> b) -> f a -> f b

It seems that are the same:

*TextGame> (*2) <$> [1..3]
[2,4,6]
*TextGame> fmap (*2) [1..3]
[2,4,6]

But, actually they are different:

*TextGame> map describePath <$> lookup situacio edges
Just ["There is door going west from here.","There is ladder going upstairs from here."]
*TextGame> fmap (describePath) (lookup situacio edges)

<interactive>:30:22: error:
    • Couldn't match type ‘[Lloc]’ with ‘Lloc’
      Expected type: Maybe Lloc
        Actual type: Maybe [Lloc]
        ....

Could someone put a little more light on it ? I do not fully understand why 'fmap (describePath) (lookup situacio edges)' do not work? (I am playing with Maybe's and Just's but ...)

Upvotes: 1

chi
chi

Reputation: 116139

There might be some more advanced library helpers, but I think you should first learn how to handle Maybes in the most basic (and general) way: use pattern matching.

case lookup situacio edges of
   Nothing   -> [] -- not found, how do you want to handle this case?
   Just locs -> map describePath locs

Oftentimes, one wants instead to rewrap the result in another Maybe, e.g.:

case lookup situacio edges of
   Nothing   -> Nothing -- not found
   Just locs -> Just (map describePath locs)

and in such case, we can use a library helper function to shorten the code:

map describePath <$> lookup situacio edges

Upvotes: 6

Related Questions