4

I am learning Jason Hickey's Introduction to Objective Caml.

After I learned Chapter 3, I seem to understand how the let and fun work. But still, I have troubles to write my own fun.


Here is an example problem I am facing.

Write a function sum that, given two integer bounds n and m and a function f, computes a summation (no for loop allowed). i.e., sum n m f = f(n) + f(n+1) + ... + f(m)


So, how should I start to think about producing this function sum?

In Java or normal programming language, it is easy.

Since here for loop is not allowed, so I guess I should do it in let rec way?

Something like this:

let rec sum n m f = fun i -> ....

I need an i to be a cursor?

Whatever, I can't continue to think out.

Can anyone point a road for me to produce a OCaml fun?


This is my final solution:

let rec sum n m f = if n <= m then (f n)+(sum n+1 m f) else 0;;

but of course, it is wrong. The error is Error: This expression has type 'a -> ('a -> int) -> 'b but an expression was expected of type int

Why? and what is 'a?

Jackson Tale
  • 25,428
  • 34
  • 149
  • 271

3 Answers3

6

You have done a classic syntax mistake: sum n+1 m f is parsed as (sum n) + (1 n f) instead of what you expect. In OCaml, function application (space) has stronger precedence than infix operators.

The type error comes from the fact that sum n (which you use in a sum) is not an integer. It takes one more argument (m) and a function returning an integer. At this point of the type inference process (when the error occurs), OCaml represents this as 'a -> ('a -> int) -> 'b: takes some unknown stuff a, a function from a to int, and returns some stuff b.

gasche
  • 31,259
  • 3
  • 78
  • 100
  • Yes, thanks, I corrected it to `sum (n+1) m f`, it works fine now. But could you please tell me how to think in producing a `fun`? The logic is quite different from other easy programming language. – Jackson Tale Dec 04 '12 at 15:27
  • @JacksonTale doing this is not explained in a comment, it's explained by being a functional programmer for a while and forcing yourself to work through some examples. – Kristopher Micinski Dec 04 '12 at 15:31
6

I'm hoping this will help you to think in terms of recursion and not with loops (let's leave out tail recursion for a moment).

So you need to calculate f(n) + f(n+1) + ... f(m). It might help you to think of this problem in an inductive fashion. That is, assume you know how to calculate f(n+1) + ... + f(m), then what do you need to do in order to calculate the original result? well, you simply add f(n) to the latter, right? That is exactly what your code has to say:

let rec sum n m f =
  if n = m then
    f m
  else
    f n + sum (n + 1) m f;; (* here's the inductive step *)

You can see how I have added f(n) to the result of f(n+1) + .... + f(m). So, think inductively, break down the problem into smaller pieces and think about how you can put the results of those smaller pieces together.

Hope I didn't make things more confusing.

Asiri Rathnayake
  • 1,138
  • 1
  • 11
  • 27
  • let rec sum1 n m f = sum2 n m 0 and sum2 n m s = if n <= m then sum2 (n+1) m (s+f n) else s;; is this one tail recur? – Jackson Tale Dec 04 '12 at 16:58
  • 2
    Yes, the idea is that you use an **accumulator** to keep track of the sum calculated so far. So you are accumulating the sum as you go along the calculation... so at the end you can simply return the accumulated value. This avoids the need to operate on a result returned for a sub-problem (i.e, you can immediately return the result for the sub-problem). – Asiri Rathnayake Dec 04 '12 at 17:16
1

'a is like the generic type in Java. For example: let test a = 1 Its type is 'a -> int This function would return 1 regardless of the type of your argument.

The error is that you need to put parentheses here (sum (n+1) m f)

Ocaml thought of it as extra arguments, and so it results in a different type than as you intended. Putting parentheses would make sure you have the right number of arguments. It is a subtle problem to debug when you have a lot of codes. So using parentheses in similar situations would save you so much time. :)

clouddreams
  • 622
  • 1
  • 4
  • 13