1

Here is my current code, I want to be able to create a MAIN IO that acts as an interface and allows the user to pick which functions to execute depending on their choice.

type Title = String
type Actor = String
type Cast = [Actor]
type Year = Int
type Fan = String
type Fans = [Fan]
type Period = (Year, Year)
type Film = (Title, Cast, Year, Fans)
type Database = [Film]
title (t, _, _, _) = t
cast (_, c, _, _) = c
year (_, _, y, _) = y
fans (_, _, _, fs) = fs

testDatabase :: Database
testDatabase = [("Casino Royale", ["Daniel Craig", "Eva Green", "Judi Dench"], 2006, ["Garry", "Dave", "Zoe", "Kevin", "Emma"]),
    ("Cowboys & Aliens", ["Harrison Ford", "Daniel Craig", "Olivia Wilde"], 2011, ["Bill", "Jo", "Garry", "Kevin", "Olga", "Liz"]),     
        ("Catch Me If You Can", ["Leonardo DiCaprio", "Tom Hanks"], 2002, ["Zoe", "Heidi", "Jo", "Emma", "Liz", "Sam", "Olga", "Kevin", "Tim"])]

Function 1:

displayAllFilms' :: [Film] -> String -> String
displayAllFilms' [] filmString = filmString
displayAllFilms' ((title,cast,year,fans):films) filmString = 
       displayAllFilms' films (filmString ++ "\n" ++ title ++ ", " ++ listStuff cast ", " ++ (show year) ++ ", " ++ show (length fans))

Function 2:

filmsByFan f = map title $ filter (elem f . fans) testDatabase

The above code is 100% working and I am able to pull the information out of the given database.

Here is the example MAIN IO that I have created:

main :: IO ()
main = do putStrLn "What function would you like to execute? 1. addFilm / 2.displayAllFilms / 3. filmsByYear / 4. filmsByFan / 5. filmsByActor Period / 6. becomeFan: "
          str <- getLine
          if str /= "2"
            then return ()
            else do putStrLn (displayAllFilms' testDatabase str)
          if str /= "4"
            then return ()
            else do putStrLn "Enter an existing fan: "
                    name <- getLine
                    putStrLn filmsByFan name  <<< **error here**
                    main

The problem I am having is when more than 2 functions are applied to the IO if statement, it doesn't seem to register when 'name' is assigned by a user input and thus the rest of the code from name <- getLine does not compile.

My question is: Is there a way for the user to select what function to execute depending on what they have chosen and execute the appropriate function...?

Thanks in advance!

Edit:

Example on how I wish the code to execute:

Main
which function would you like to execute...1,2,3,4,5,6?
user enters: 1
displayFilms will execute.

IF USER ENTERS 4

user enters: 4
Enter an existing fan:
user enters: Liz"
execute filmsByFan
8
  • Sorry, I don't understand. Is your problem with the code you've posted? If so, please copy+paste in the full error message. Or, is your problem with some other code that you're not showing us? In that case, please copy+paste that code into your question (and the full error message as well). I don't understand what you mean by “more than 2 functions are applied to the IO if statement” and I don't want to guess. Commented Apr 23, 2013 at 17:46
  • The problem seems to be that entering e.g. "3" will make both "menu items" appear. The solution is of course to use == instead of /=, or a case..of expression. One could also use the when function. Commented Apr 23, 2013 at 17:57
  • main :: IO () is the code im stuck on..pasted above. The error message im getting is: ExampleSolution.hs:167:12: parse error on input `do' Basically what I want to do is, when executing main, the user is able to choose which function to run by typing either 1, 2, 3, 4...If 1 is chosen then it will run displayFilms function and it will prompt the user to enter the appropriate parameters to satisfy the funtion and then it will execute displayFilms; now if 4 was chosen it will run filmsByFan to which it will prompt the user to enter an existing fan corresponding to the database. SEE EDIT Commented Apr 23, 2013 at 18:00
  • by the way, here's where you might also want to pass the film-list-database as an argument to main (main myFilmListArgument), and use it in the interactive functions, rather than the global film list value, so you can pass the updated version back into the loop. Commented Apr 23, 2013 at 18:06
  • the Main IO, is only part of the code, only selections 1 and 4 work, so long as it allows the user to differentiate which function to run I am then able to build around this and thus finally completing the main IO with all 6 functions implemented. Commented Apr 23, 2013 at 18:07

2 Answers 2

1

You say the error message you get is

ExampleSolution.hs:167:12: parse error on input `do'

You don't say which line is line 167.

You appear to be mixing spaces and tabs. This may be the cause of the problem. Replace all tabs in your source code with spaces.

Edit: I said you appear to be mixing spaces and tabs because the source code in your question mixes spaces and tabs. e.g. the indentation of the line with the error ends with tabs, whereas the indentation in the line above it ends with eight spaces and does not appear to be indented as far.

This is consistent with the lines

name <- getLine
putStrLn filmsByFan name

actually being

name <- getLine
        putStrLn filmsByFan name

and being interpreted as

name <- getLine putStrLn filmsByFan name

which would cause the error you now report:

ExampleSolution.hs:174:61: Not in scope: `name'

as name is defined on the left of the <- and thus not available for use on the right: it is only available for use in subsequent lines in the block.

Check that your editor is not converting spaces to tabs when it saves your file, contrary to your wishes. Alternatively, ensure that it uses 8-space-wide tabs (I would guess that you're probably using 4-space-wide tabs).

n.b. You probably intend for these lines to read

name <- getLine
putStrLn (filmsByFan name)
Sign up to request clarification or add additional context in comments.

2 Comments

Sorry the error code is: ExampleSolution.hs:174:61: Not in scope: `name' - I copy and pasted the wrong one. This corresponds to this line: putStrLn filmsByFan name, I also have not tabbed any of my indentations all have been spaced appropriately.
i've edited the original post displaying where the error lies. see edit.
1

You could put all the functions in a table, and use lookup to select which one to run.

table = [(1, addFilm)
        ,(2, displayAllFilms)
        ,(3, filmsByYear)
        ,(4, filmsByFan)
    ]

I renamed your filmsByFan to filmsByFan' (prime), so I could add a layer to prompt for the key and call your orig function:

filmsByFan = do putStr "Enter Fan"
                f <- getLine
                print $ filmsByFan' f               
filmsByFan' f = map title $ filter (elem f . fans) testDatabase
main :: IO ()
main = do putStrLn "What function would you like to execute? 1. addFilm / 2.displayAllFilms / 3. filmsByYear / 4. filmsByFan / 5. filmsByActor Period / 6. becomeFan: "
          str <- getLine
          let n = (read str)::Int
              cmd = lookup n table
          case cmd of
            Just doIt -> doIt
            Nothing   -> do print "sorry"
                            main

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.