0

I have these functions in Haskell:

 type World = [String]

 look :: World -> IO World
 look w = do
   putStrLn $ "You are here " ++ show w
   return w

 test w = do
      words <- fmap words getLine
      case words of
        ("quit":_) -> return ()
        ("look":_) -> do w' <- area w'; describe w'
        ("remove":item:_) -> do w' <- removeItem item w; loop w'
        _ -> do putStrLn "Wrong input"; test w

area::String->String
area place =
  return place

describe:: String ->String
describe place =
  case place of
    "usa" -> putStrLn "It is usa"
    "uk" -> putStrLn "It is uk"
    "aur" -> putStrLn "It is aus"

main = do
  let world0 = ["ht", "alt"]
  let place = ["usa"]
  area place
  print place
  test world0 

In the line

("look":_) -> do w' <- area w'; describe w'

I want to call the "area" function that returns a place entered in main and the describe function to return the description for that place. How can I do that?

2
  • Here is a simple adventure game written in Haskell which might help with program organization: link Commented Nov 10, 2014 at 16:39
  • 1
    Shouldn't area and describe have the types String -> IO String and String -> IO () respectively? You're using return and putStrLn in these functions, so they have to return a monadic value Commented Nov 10, 2014 at 16:46

2 Answers 2

2

In this case your world consists of two items of state:

  • where you are, and
  • what items you have

so type World = [String] isn't going to work. You'll need something like:

type World = (String, [String])  -- (where, items)
-- or:
data World = World { where_ :: String, items_ :: [String] }

and now functions like removeItem, describe have to be reworked.

For example, suppose we have type World = (String,[String]). Then describe would go like:

describe :: World -> IO ()
describe (place,_) =
  case place of
    "usa" -> ...
    "uk" -> ...
    ...other cases...
Sign up to request clarification or add additional context in comments.

Comments

0

If you want to maintain state between the two functions (main and test), you may use an IORef for this.

test w ref = do
  -- when you need to read it:
  place <- readIORef ref

i_am_at = writeIORef

main = do
  let world0 = ["ht", "alt"]
  let place = ["usa"]
  ref <- newIORef place -- creates the ref with initial value
  i_am_at ref place -- needs reference
  print place
  test world0 ref

But, this goes totally in the wrong direction. It's not Haskell's idiomatic way of doing things. Essentialy, you are reproducing imperative code in a functional language.

Try to refactor your code in a way that you do not need mutable variables, building a State Machine can be a good start.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.