开发者

Can't get my head around primitive recursion definitions in haskell

开发者 https://www.devze.com 2023-03-04 01:12 出处:网络
I\'ve got a good idea of what primitive recursive definitions are, however I still can\'t seem to get my head around it.

I've got a good idea of what primitive recursive definitions are, however I still can't seem to get my head around it.

For example, I can't seem to explain to myself how to do the following (yet I seem to be able to do it):

Exercise:

Define the function productIt :: [Int] -> Int which gives the product of a list of integers, and returns 1 for an empty list; why is this particular value chosen as the result for the empty list?

I (of course) came up with the solution:

productIt :: [Int] -> Int
productIt [] = 1
productIt (x:xs) = x * productIt xs

which works perfectly for the question in the exercise. Yet I still seem to ha开发者_开发技巧ve trouble getting my head around the final line.

Any ideas on how to think this out would be most appreciated.


In English, you could read that final line as:

The product of a list of numbers is the first number times the product of the rest of the numbers. And if there are no numbers, let's just say the product is 1.

Converting it to English like this usually helps me understand how and why a recursive function works. You could also evaluate it with the Haskell interpreter inside your head:

  productIt [2,3,4]
= 2 * (productIt [3,4])
= 2 * (3 * (productIt [4]))
= 2 * (3 * (4 * (productIt [])))
= 2 * (3 * (4 * (1)))
= 2 * (3 * (4))
= 2 * (12)
= 24


The reason you use 1 for the trivial case [] is because it doesn't change the result when you multiply by it.

productIt (x:xs) = x * productIt xs

Suppose, for example, you defined it like this:

productIt [] = 2                      -- line 1
productIt (x:xs) = x * productIt xs   -- line 2

Then consider:

productIt [1] = productIt (1:[])
              = 1 * productIt []    -- by line 2
              = 1 * 2               -- by line 1
              = 2                   -- WRONG!!!

You're looking for the product of the list of integers, and for [1] the answer should be 1.


Before I explain that final line of code, let me summarise the process for solving this type of problem. There are two key questions:

  1. What's the simplest possible case?
  2. Can I express the solution in terms of the next simplest solution?

OK, so we want to write a function that calculates the product of all the numbers in a list.

Re question 1: The simplest possible case is that there aren't any numbers. If this is the first time I've encountered the problem, it might not be obvious to me what the answer should be in this case, but let's put that aside for the moment.

Re question 2: If I have a list [n0, n1, n2,.. nk], and somehow I know the product (let's call it p) of all the numbers except the first one, then the answer is the first element times that product, or n0 * p.

The first line of code will take care of the trivial case:

productIt [] = 1

That says that the function productIt for the empty list argument, [], has the value 1. (I explained above why the answer has to be 1.) That takes care of the trivial case. Now we need to define productIt in the case where the list isn't empty. Let's look at that last line of code:

productIt (x:xs) = ... something?

The left-hand side uses pattern matching. The pattern (x:xs) will match a list with one or more elements. When that expression is matched, it binds x to the first element, and xs to the rest of the list. So not only are we matching the pattern, we're getting x and xs defined as a bonus. That's what makes pattern matching really powerful in Haskell.

So if the first element of the list is x, and the rest of the list (all but the first element) is xs, then what is the answer? We've already decided that it's the first element (x) times the product of all the remaining elements (xs). So...

productIt (x:xs) = x * productIt xs

Also, yjerem gave you an excellent explanation of how Haskell would evaluate it.

0

精彩评论

暂无评论...
验证码 换一张
取 消