I'm brand spanking new to Haskell and functional programming in general so I'm having a little trouble iterating through a list to get the product.
IntList is defined as:
data IntList = Nil | Cons Integer IntList deriving (Show, Eq, Ord)
My head immediately goes to some sort of recursion but I don't know how to move to the next element. Right now all I have is:
prod :: IntList -> Integer
prod x =
if(x == Nil)
then 1
else x (Pretty sure x makes no sense here) * prod (No idea what to put here)
Does anybody have any guidance?
CodePudding user response:
The canonical way to consume data is via pattern matching.
prod x = case x of
Nil -> {- you fill in here -}
Cons n y -> {- you fill in here -}
In fact, this idiom of accepting an argument and immediately pattern matching on it is such a common way of defining functions that there is special syntax for it. The following is equivalent, except that the name x
does not exist in the body of the function:
prod Nil = {- you fill in here -}
prod (Cons n y) = {- you fill in here -}
CodePudding user response:
Your x
is an IntList
. We say x
is of type IntList
(written as x :: IntList
) to distinguish it from variables of other types (say Int
or String
). Since you have x :: IntList
you check the data declaration
data IntList = Nil | Cons Integer IntList deriving (Show, Eq, Ord)
and conclude that x
is either a Nil
or a Cons
(we call Nil
and Cons
data constructors). Distinguishing between the two is done using pattern matching and Daniel's answer explains it in more detail. The difference between Nil
and Cons
is that the later has two parameters: a value of type Integer
and a value of type IntList
. Part of pattern matching is, that you give those values names (what we call bind a value to a name). In the case of Cons n y
those values have been bound to n
and y
.
There might be another confusing thing going on. Looking again at your IntList
, those are some example values:
empty_list = Nil
l1 = Cons 1 Nil
l2 = Cons 1 (Cons 2 Nil)
l3 = Cons 1 (Cons 2 (Cons 3))
So you see this way of thinking about a list is probably different from what you have seen before. If you take a look at l3
you might notice that you can access the 1 (the head) of the list more easily than values deeper down in the tail:
case l3 of
Cons head tail -> head -- here head == 1
To sum up you have to deal with three concepts:
- Pattern matching to distinguish the different constructors and binding their parameter values to names,
- a strange/new way of looking at lists,
- your actual problem of multiplying the items of a list.
So there is no doubt that this seemingly innocent exercise can be quite a bit overwhelming.