Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell Cons Operator (:)

I am really new to Haskell (Actually I saw "Real World Haskell" from O'Reilly and thought "hmm, I think I'll learn functional programming" yesterday) 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).

like image 381
Carson Myers Avatar asked Apr 27 '09 21:04

Carson Myers


2 Answers

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]
like image 150
sth Avatar answered Oct 14 '22 10:10

sth


As a recovering ML programmer, I get caught by this one all the time. It's one of the few annoyances in Haskell that you cannot easily rebind a name in let or where clauses. If you want to use let or where, you have to invent new names. At the top-level read-eval-print loop, if you want to bind one name at a time, you have no other choice. But if you are willing to nest constructs, you can abuse the do notation with the identity monad:

import Control.Monad.Identity

let order_list = runIdentity $ do
       order_list <- return [Invoice 2345]
       order_list <- return $ CashOnDelivery : order_list
       return order_list

Yes, this code is despicable---and not worth it for this example---but if I have a long list of rebindings I might resort to it so I don't have to invent 5 or 6 meaningless variations on the same name.

like image 35
Norman Ramsey Avatar answered Oct 14 '22 11:10

Norman Ramsey