[Haskell-cafe] Getting started

Mark Lentczner markl at glyphic.com
Mon Jul 5 12:56:05 EDT 2010


On Jul 5, 2010, at 7:50 AM, Mrwibbly wrote:

> This adds the data to an empty database but I can't seem to call newRecord
> again and add another record to the existing database.

The issue is that you need to use the new database returned by newRecord in subsequent executions of your main loop. I've coded a simpler data example showing how to do this:

> --
> -- Pure, Functional Data Set
> --
> type Name = String
> type DB = [Name]
> 
> addName :: String -> DB -> DB
> addName name db = name : db
> 
> initialDB :: DB
> initialDB = [ "Amy", "Bob" ]
> 
> --
> -- UI Actions on DBs
> --
> addNameAction :: DB -> IO DB
> addNameAction db = do
>     putStrLn "Enter name to add:"
>     name <- getLine
>     return $ addName name db
> 
> printNames :: DB -> IO ()
> printNames db = mapM_ print db
> 
> --
> -- Main Program
> --
> mainLoop :: DB -> IO ()
> mainLoop db = do
> 	putStrLn "1 = Add a name to the DB"
> 	putStrLn "2 = Print the DB"
> 	putStrLn "3 = Exit"
> 	input <- getLine
> 	case read input of
> 	   1 -> do
> 	           newDB <- addNameAction db
> 	           mainLoop newDB
> 	   2 -> do
> 	           printNames db
> 	           mainLoop db
> 	   3 -> do
> 	           return ()
> 
> main :: IO ()
> main = mainLoop initialDB

Notice how mainLoop is called recursively after the input is handled. This is how the changes to the database are propagated from one action to the next.

Note: mainLoop is rather verbose, you would generally find this written as:

> mainLoop :: DB -> IO ()
> mainLoop db = do
> 	putStrLn "1 = Add a name to the DB"
> 	putStrLn "2 = Print the DB"
> 	putStrLn "3 = Exit"
> 	input <- getLine
> 	case read input of
> 	   1 -> addNameAction db >>= mainLoop
> 	   2 -> printNames db >> mainLoop db
> 	   3 -> return ()

Once you've got that under your belt, consider this version, which is even more general:

> actions :: [(String, DB -> IO ())]
> actions = [
>     ("Add a name to the DB",    \db -> addNameAction db >>= mainLoop),
>     ("Print the DB",            \db -> printNames db >> mainLoop db),
>     ("Exit",                    \db -> return ())
>     ]
> 
> mainLoop :: DB -> IO ()
> mainLoop db = do
>     mapM_ print $ zip [1..] $ map fst actions
>     input <- getLine
>     let action = snd $ actions !! (read input - 1)
>     action db

	- Mark



Mark Lentczner
http://www.ozonehouse.com/mark/
IRC: mtnviewmark





More information about the Haskell-Cafe mailing list