haskellfunctional-programmingoperators

Haskell Cons Operator (:)


I am really new to Haskell and I am wondering: I can use the construct operator to add an item to the beginning of a list:

1 : [2,3]
[1,2,3]

I tried making an example data type I found in the book and then playing with it:

--in a file
data BillingInfo = CreditCard Int String String
| CashOnDelivery
| Invoice Int
deriving (Show)

--in ghci
 $ let order_list = [Invoice 2345]
 $ order_list
[Invoice 2345]
 $ let order_list = CashOnDelivery : order_list
 $ order_list
[CashOnDelivery, CashOnDelivery, CashOnDelivery, CashOnDelivery, CashOnDelivery, CashOnDelivery, CashOnDelivery, CashOnDelivery, CashOnDelivery, CashOnDelivery, CashOnDelivery, CashOnDelivery, CashOnDelivery, CashOnDelivery, ...-

etc... it just repeats forever, is this because it uses lazy evaluation?

-- EDIT --

okay, so it is being pounded into my head that let order_list = CashOnDelivery:order_list doesn't add CashOnDelivery to the original order_list and then set the result to order_list, but instead is recursive and creates an infinite list, forever adding CashOnDelivery to the beginning of itself. Of course now I remember that Haskell is a functional language and I can't change the value of the original order_list, so what should I do for a simple "tack this on to the end (or beginning, whatever) of this list?" Make a function which takes a list and BillingInfo as arguments, and then return a list?

-- EDIT 2 --

well, based on all the answers I'm getting and the lack of being able to pass an object by reference and mutate variables (such as I'm used to)... I think that I have just asked this question prematurely and that I really need to delve further into the functional paradigm before I can expect to really understand the answers to my questions... I guess what i was looking for was how to write a function or something, taking a list and an item, and returning a list under the same name so the function could be called more than once, without changing the name every time (as if it was actually a program which would add actual orders to an order list, and the user wouldn't have to think of a new name for the list each time, but rather append an item to the same list).


Solution

  • You do this:

    $ let order_list = [Invoice 2345]
    $ let order_list = CashOnDelivery : order_list
    

    The important thing to note here is that you are not just adding a CashOnDelivery item to your first order_list. You are defining a new variable order_list that has nothing to do with the first one. This is a recursive definition, the order_list on the right side refers to the order_list you are defining on the left, not the one defined in the previous line. Because of this recursion you get an infinite list.

    I suspect you really wanted to do something like this:

    $ let order_list = [Invoice 2345]
    $ order_list
    [Invoice 2345]
    $ let order_list2 = CashOnDelivery : order_list
    $ order_list2
    [CashOnDelivery, Invoice 2345]