Linda Su
Linda Su

Reputation: 455

How to store values in a list from if statements

Hi I have these functions:

i_am_at::String->String
i_am_at place =
  place

at::String-> (String, String)
at place =
  case place of
    "bedroom" -> ("fly", "light switch")
    "den" -> ("flyswatter", "light switch")

main::IO()
main = do
  putStrLn "Enter place"
  p <- getLine :: IO String
  i_am_at p

I want to write a function "take" that takes an argument "item" and calls the i_am_at function which returns a string "place", and then calls the "at" function with the string returned by the i_am_at function, and then checks if the item is a light switch when place is bedroom, then store it into a array and return it. But, if item is fly then don't store it. Similarly, if place is den and the item is either from the two then store it into that array. I am doing something like this:

take::String->String[],IO() 
take item =
  plc = i_am_at
    | plc == "bedroom" && item == "light switch" && item not present in list y already (I don't know how to write this condition)
      y = item
    | plc == "bedroom" && item == "fly" && item not present in list y already (I don't know how to write this condition)
      = putStrLn "You cannot take that"
    | plc == "den" && item == "flyswatter" && item not present in list y already (I don't know how to write this condition)
      y = item
    | plc == "den" && item == "light switch" && item not present in list y already (I don't know how to write this condition)
      y = item
    | if item present in list y already
      = putStrLn "You already have it"
    | Otherwise = putStrLn "Item is not here"
    return y

Could somebody help me fix this function. y is a list in this function, but I don't know how to store values in it. I also don't know how can we have a return type that's returning a value as well and printing it out too. I also don't know if the statement plc=i_am_at is correct or not. How to make this work?

Upvotes: 0

Views: 105

Answers (1)

ErikR
ErikR

Reputation: 52049

In a pure functional language like Haskell you emulate mutable state with the following recipe:

  1. Define a data structure which contains everything which could change (let's call it World)
  2. Write all of your state modifying functions to have the signature World -> World (or, perhaps World -> IO World if you need to perform IO. The function creates a new world value from an existing one.
  3. Chain all of your function calls so that the output world from one call is passed as the input to the next function.

Example: Let's say your world consists of just a list of items (Strings):

type World = [String]

To remove an item you would write a function like:

removeItem :: String -> World -> IO World
removeItem item world = do
  if elem item world
    then do putStrLn "Item removed."
            return $ delete item world
    else do putStrLn "No such item - " ++ item
            return world

Then you can remove two items with:

removeTwoItems a b world = do
  world1 <- removeItem a world
  world2 <- removeItem b world
  return world2

There are advanced mechanisms (like the State monad) to help you with these kinds of patterns, but this is essentially what is going on.

An more complete example showing how to integrate this patterns into an application:

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

loop w = do
  words <- fmap words getLine
  case words of
    ("quit":_) -> return ()
    ("look":_) -> do w' <- look; loop w'
    ("remove":item:_) -> do w' <- removeItem item w; loop w'
    _ -> do putStrLn "huh?"; loop w

main = do
  let world0 = ["chair", "bucket"] -- the initial world
  loop world0

Upvotes: 2

Related Questions