2016-12-03 8 views
2

Мне нужно проверить все возможные комбинации в 5-элементном массиве в OCaml, если какая-либо комбинация соответствует условию, я должен остановиться для циклов и вернуть этот массив, но не легко вернуть что-то в для ...«Перерыв» для цикла в OCaml

у меня есть этот код:

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

но говорит: Ошибка: Это выражение имеет тип цвета массив но выражение ожидалось единицы типа

Как я могу вернуться массив, который соответствует co ndition?

ответ

3

Давайте раскроем ваше сложное определение функции, заменив ваш большой цикл цикла на <big-for-loop>.

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

<big-for-loop> является actualy выражение, значение которого () имеет блок типа. Выражение try/with, имеет следующий синтаксис:

try e1 with exn -> e2 

Оба e1 и 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;; 
+0

Это не работает, я сделал исключение ExitArray из массива цветов ;; " а затем «поднять (ExitArray arraycolores)» и, наконец, «с помощью ExitArray arraycolores-> arraycolores ;;" но он все еще говорит: «Ошибка: это выражение имеет тип color array , но ожидалось выражение от единицы типа« – gmv92

+0

не связано ли это с тем, что конструктор if не имеет ветви else? вы должны добавить его: else arraycolours - таким образом не будет больше несоответствия между результатом, созданным конструкциями lop (который является единицей в вашем текущем коде) и исключением. –

+0

Я так не думаю, что я поставил другое с тем же (raise (ExitArray arraycolores)) только для тестирования, он говорит то же самое – gmv92

2

Ваша проблема заключается в том, что как тело try заявление должно возвращать значение того же типа, что и п with. Однако в вашем примере тело имеет блок типа и with, тип colour array (или что-то в этом роде).

Что вам нужно сделать, зависит от того, приведет ли конец цикла к результату или ошибке.

Если это даст результат, у вас есть два варианта. Во-первых, вы можете просто добавить ; arraycolours после последнего done, чтобы вернуть массив. Во-вторых, вы можете вместо этого использовать ; raise Exit после последних done.

Если вы достигнете конца цикла, это будет ошибка, вы должны создать другое исключение, например. ; failwith "this cannot happen" после окончательного done.

+0

Другой возможностью было бы вернуть «Нет», если соответствующие массивы не найдены и «Некоторые arraycolors» в противном случае. – hugomg

+0

Wooow, очень спасибо, он работает !! @hugomg он никогда не вернет None, всегда будет действительный массив, так что он не нужен – gmv92

+0

Тогда я бы добавил 'assert false' в конце циклов, чтобы он ясно дал понять, что достичь этой точки никогда не должно быть. 'Assert_failure' также менее вероятно, будет невольно пойман, чем' Failure'. – ChriS