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).
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]
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With