3
votes

I need to test all possible combinations in a 5 element array in OCaml, if any combination meets a condition, I must stop for loops and return that array, but is not easy return something in a for...

I have this code:

let myfunction t =
 let arraycolours = Array.make 5 W in
  try
   for i=0 to 3 do
    Array.set arraycolours 0 (inttocolour i);
    for j=0 to 3 do
     Array.set arraycolours 1 (inttocolour j);
     for k=0 to 3 do
      Array.set arraycolours 2 (inttocolour k);
      for l=0 to 3 do
       Array.set arraycolours 3 (inttocolour l);
       for m=0 to 3 do
        Array.set arraycolours 4 (inttocolour m);
        if test arraycolours = t then raise Exit
       done
      done
     done
    done
   done
  with Exit -> arraycolours;;

But there says: Error: This expression has type colour array but an expression was expected of type unit

How can I return the array that meets condition?

3

3 Answers

4
votes

Let's collapse your complex function definition by substituting your big for loop with the <big-for-loop> term.

let myfunction t =
 let arraycolours = Array.make 5 W in
  try
    <big-for-loop>
  with Exit -> arraycolours

The <big-for-loop> is actualy an expression, whose value () has type unit. The try/with expression, has the following syntax:

  try e1 with exn -> e2

Both e1 and e2 must return values of the same type. In you case the <big-for-loop> expression returns a value of type unit and the expression under the with clause has type colour array. This basically means, that depending on whether you were able to find a combination or not, your function will have different types. But types in OCaml can't depend on the runtime values, so we have a type error.

There are different solutions, depending on what you trying to implement, for example, you can raise Not_found exception if a combination wasn't found, e.g.,

let myfunction t =
 let arraycolours = Array.make 5 W in
  try
    <big-for-loop>;
    raise Not_found
  with Exit -> arraycolours

Alternatively, you can wrap the result into option type, and return Some array if the combination is found, and None otherwise:

let myfunction t =
 let arraycolours = Array.make 5 W in
  try
    <big-for-loop>;
    None
  with Exit -> Some arraycolours

I, personally, would prefer the latter solution.

2
votes

You should define a new exception type :

exception ExitArray of <type of arraycolor> (* may be "int array" in your case *) 

Then, when you want to exit from your loops : you raise an exception raise ExitArray arraycolors , at the end you catch the exception and collect the result:

  with Exit a -> a;;
2
votes

Your problem is that both the body of the try statement needs to return a value of the same type as the with clause. However, in your example, the body has type unit and the with clause type colour array (or something like that).

What you have to do depends on whether reaching the end of the loop should yield a result or an error.

If it should yield a result, there are two options you have. First, you can simply add ; arraycolours after the last done to return the array. Second, you can instead use ; raise Exit after the last done.

If reaching the end of the loop would be an error, you should instead raise a different exception, e.g. ; failwith "this cannot happen" after the final done.