OCaml中如何“打破”for循环

3

我需要在OCaml中测试一个5元素数组的所有可能组合,如果任何组合符合条件,我必须停止循环并返回该数组,但在for循环中返回结果并不容易...

我有以下代码:

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;;

但是报错说: 错误:此表达式的类型为颜色数组,但需要一个类型为单元的表达式。

我该如何返回符合条件的数组?

3个回答

4

通过用<big-for-loop>代替您的大型循环,让我们简化您复杂的函数定义。

let myfunction t =
 let arraycolours = Array.make 5 W in
  try
    <big-for-loop>
  with Exit -> arraycolours
< p > <big-for-loop> 实际上是一个表达式,其值 () 具有单位类型。 以下是 try/with 表达式的语法:

  try e1 with exn -> e2

需要同时返回值的类型相同,你的情况下<big-for-loop>表达式返回了一个unit类型的值,而with子句下面的表达式则是colour array类型。这基本上意味着,根据您是否能够找到组合,您的函数将具有不同的类型。但是,在OCaml中,类型不能依赖于运行时值,因此我们有一个类型错误。

根据您要实现的内容,有不同的解决方案,例如,如果未找到组合,则可以引发Not_found异常,例如:

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

或者,您可以将结果包装成选项类型,并在找到组合时返回Some array,否则返回None

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

我个人更倾向于后者的解决方案。

2

您应该定义一个新的异常类型:

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

当你想从循环中退出时:你可以抛出一个异常raise ExitArray arraycolors,最后捕获异常并收集结果:

  with Exit a -> a;;

它不起作用,我已经执行了“exception ExitArray of colour array;;”,然后是“raise (ExitArray arraycolores)”,最后是“with ExitArray arraycolores-> arraycolores;;”,但它仍然显示“错误:此表达式的类型为colour array,但期望一个类型为unit的表达式”。 - gmv92
这难道不是因为 if 结构没有 else 分支的原因吗?你应该添加它:else arraycolours - 这样就不会再出现循环结构(在你当前的代码中是 unit)和异常捕获提供的结果不匹配的情况了。 - Pierre G.
我不这么认为,我已经放了一个else语句并使用相同的(raise(ExitArray arraycolores))进行测试,结果显示相同。 - gmv92
问题在于你的函数没有返回相同的类型 - 这就是 Ocaml 给你的提示。当你引发异常时,你的函数返回一个数组。那么,当你的函数不引发异常时,结果的类型是什么? - Pierre G.
你是对的,我已经在最后一个“done”中添加了“; arraycolores”,现在没问题了。非常感谢Pierre! - gmv92

2
你的问题在于try语句体需要返回与with从句相同类型的值。然而,在你的示例中,try语句体的类型是unit,而with从句的类型是“颜色数组”(或类似的类型)。
解决方法取决于循环结束时应该产生结果还是错误。
如果应该产生结果,则有两个选项。首先,在最后一个done后面添加“; arraycolours”,以返回数组。其次,你可以在最后一个done后面使用“; raise Exit”。
如果到达循环结束是一个错误,你应该引发不同的异常,例如,在最后一个done后面添加“; failwith"this cannot happen"”。

另一种可能性是如果找不到合适的数组,则返回None,否则返回Some arraycolors - hugomg
哇,非常感谢,它起作用了!! @hugomg它永远不会返回None,总会有一个有效的数组,因此不必这样做。 - gmv92
然后我会在循环的末尾添加 assert false,以便清楚地表明不应该到达那个点。Assert_failure 也比 Failure 更不容易被无意中捕获。 - ChriS

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接