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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.