A simple example Haskell application

I’m currently trying to cram Haskell into my brain, and in an effort to do so, I’ve been writing a fake POS (point of sales) application. It has a command-line UI that prompts the user to add Pizzas and a Customer to an Order.

I need to re-organize the code, but this is what about 50% of the code looks like right now. The other 50% is in a module that defines what a Pizza is, and also defines its helper functions.

Example Haskell source code (pizza order entry system)

So, without further ado, here is some sample source code that represents what I know about Haskell so far:

import System.IO
import Pizza


-- TODO add breadsticks, soft drinks, etc.
data Order = Order { customer :: Customer
                   , pizzas  :: [Pizza]
                   } deriving (Show)

-- TODO expand the concept of a customer
data Customer = Customer { name :: String } deriving (Show)

createEmptyOrder :: Order
createEmptyOrder = Order {customer=(Customer "no name"), pizzas=[]}

addPizzaToOrder :: Order -> Pizza -> Order
addPizzaToOrder orderIn pizzaIn =
    -- return a new Order that has the new pizza in it
    Order {customer=(customer orderIn), pizzas=newPizzas}
    where oldPizzas = pizzas orderIn       -- get the pizzas from the incoming order
          newPizzas = pizzaIn : oldPizzas  -- add the new pizza to the old pizzas

-- TODO pass in a Customer here, not a String
-- TODO the `where` clause probably isn't needed here
addCustomerToOrder :: Order -> String -> Order
addCustomerToOrder orderIn customerNameIn =
    Order {customer=(Customer customerNameIn), pizzas=oldPizzas}
    where oldPizzas = pizzas orderIn

orderToString :: Order -> String
orderToString (Order {customer = c, pizzas = p}) =
    "Customer: " ++ (show c) ++ ", Pizzas: " ++ (show p)

printOrder :: Order -> IO ()
printOrder order = do putStrLn (orderToString order)

-- MAIN --

main = do
    putStrLn "\n--- MAIN ---"
    putStrLn "1 - New Order\nq - Quit"
    line <- getLine
    case line of
        "1" -> do let order = createEmptyOrder
                  finishedOrder <- buildOrder order
                  printOrder finishedOrder
        _   -> exit

-- buildOrder --

buildOrder :: Order -> IO Order
buildOrder orderIn = do
    putStrLn "\n--- BUILD ORDER ---"
    putStrLn "1 - New Pizza\n2 - Customer\nr - Return"
    line <- getLine
    case line of
        "1"  -> do let pizza = newPizza
                   let order = addPizzaToOrder orderIn pizza
                   putStrLn "(added a pizza to the order)"
                   buildOrder order  -- recursive
        "2"  -> do customerName <- newCustomer
                   let order = addCustomerToOrder orderIn customerName
                   putStrLn "(added a customer to the order)"
                   buildOrder order  -- recursive
        "r"  -> return orderIn
        _    -> return orderIn

-- TODO return a Customer here, not a String
newCustomer :: IO String
newCustomer = do
    putStrLn "Enter Customer Name: "
    line <- getLine
    return line

newPizza :: Pizza
newPizza = Pizza {crustSize=Medium, crustType=Thin, toppings=[Cheese]}

exit :: IO ()
exit = do putStrLn ("exited")

A big thing I am trying to do in this code is handle the concept of an “order,” and also add items in an Order instance. There may be better ways to do this, but the way I handle an order that I can add things to (and eventually remove things from) is to call the buildOrder function recursively.

The user interface (text menus)

FWIW, the two “menus” in the application look as follows. First, here’s the “main” menu:

--- MAIN ---
1 - New Order
q - Quit

Next, here’s the “build order” menu:

1 - New Pizza
2 - Customer
r - Return

If you add a Pizza and a Customer to the order and return to the main menu, you’ll see output like this:

Customer: Customer {name = "John Doe"}, Pizzas: [Pizza {crustSize = Medium, crustType = Thin, toppings = [Cheese]}]


I have no doubt that this Haskell code can be improved (probably dramatically, lol), especially the way I handle a new Customer, but as mentioned, it represents what I know today.

Add new comment

The content of this field is kept private and will not be shown publicly.

Anonymous format

  • Allowed HTML tags: <em> <strong> <cite> <code> <ul type> <ol start type> <li> <pre>
  • Lines and paragraphs break automatically.