1

I am basically making a task manager where a user can add a task or print out all tasks entered. my main function contains the options of what users do...

main = do
   
   putStrLn "Below are the Options:\n\tadd\n\tprint\n\tsearch\nEnter Option:"

   input <- getLine 
   
   if input == "add" then 

       buildList []
       

   else if input == "print" then

    putStrLn "printing"

   else if input == "search" then

    putStrLn "searching"

   else
       putStrLn "Please Enter add, print, search"
   main

I am working on a function called buildList where the creation of the task happens:

buildList tasks = do
    putStrLn "Enter a Task:"

    input <- getLine

    let mytask = input

    putStrLn mytask  --here to prevent an error

..and I assume I would need a global list since I will need it if I want to print out or search within it.

mytasklist = [] 

I have been stuck on this for a while as I am new to functional programming and Haskell. I understand that I can add two list together with ++ or just do : to add at the start of the list, but I cant seem to figure out how to achieve this without an error.

update1: so would something like this work?

buildList tasks = do
    putStrLn "Enter a Task:"
    input <- getLine

    let updatedTasks = tasks ++ [input]

    main

main = do
   
   putStrLn "Below are the Options:\n\tadd\n\tprint\n\tsearch\nEnter Option:"

   input <- getLine 
   
   if input == "add" then do

    buildList []

   else if input == "print" then

    putStrLn "searchiwng"

   else if input == "search" then

    putStrLn "searching"

   else
       putStrLn "Please Enter add, print, search"
   main
3
  • 2
    As you noticed a global variable doesn't make a lot of sense, as they are immutable. Instead you would need to to have an explicit state that you take, transform and return again in each iteration. Furthermore I'd recommend loking into the case expression and guards that would simplify your if else construction. Commented Oct 18, 2021 at 8:03
  • Your question is how to have a global list you can access from everywhere? Commented Oct 18, 2021 at 8:04
  • If possible yes, in my mind as of now I would like to go through my buildlist function then append the global list with the value the user made in buildlist. Commented Oct 18, 2021 at 8:07

2 Answers 2

4

You need to rename your main function to something else, lets say go (seems to be the traditional name for this pattern) and pass your task list as a parameter to go. In the case of "add" the list you pass is the old list plus the new entry.

(Obviously this is a toy problem for learning, and this is a toy solution. Real programs have more sophisticated approaches. But this will do for now).

Sign up to request clarification or add additional context in comments.

Comments

3

Here is a simpler example, where you can increase or print an integer. You could try to adapt it to your task.

The trick is the recursive function loop, which calls itself with the updated integer.

main :: IO ()
main = do
   let loop :: Int -> IO ()
       loop n = do
          putStrLn "print/inc/quit?"
          opt <- getLine
          case opt of
             "print" -> do print n; loop n   -- recurse with the same n
             "inc"   -> loop (n+1)           -- recurse with updated n
             "quit"  -> putStrLn "bye!"      -- don't recurse to stop
             _       -> do putStrLn "invalid option, try again"; loop n
   -- call loop prividing the intial value
   loop 0

You can also make loop into a top-level function, and simply define main = loop 0, if you prefer.

There are, of course, several other more advanced options in Haskell to do this, but I'd recommend you start with the above basic approach.

When you are more familiar with the language, you could try the following alternative options:

  • the StateT Int IO monad allows IO operations and reading/writing to an Int state
  • IORefs can also be used to model mutable data

3 Comments

It's worth pointing out that loop can be a top-level function and main = loop 0.
I've seen do used to replace parentheses, but I've never seen it used to replace in before!
@jlwoodwa Inside do a;b;c each item can be of the form var <- monadicAction, monadicAction alone (with an implicit _ <- in front), and let var = expr with no in. The very last item must be monadicAction. Note that we can write let without in in list comprehensions too.

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.