Еще один способ взглянуть на это состоит в том, что у вас есть отношение эквивалентности для вашего типа; то есть, у вас есть несколько мест, где вы хотите обрабатывать все MAlpha
одинаково, все MBeta
одинаково и все MGamma
одинаково. Стандартная обработка для отношений эквивалентности состоит в том, чтобы выбрать представительный элемент, который представляет весь набор эквивалентных значений (класс эквивалентности).
В вашем случае вы можете использовать MAlpha
для представления всех MAlpha
s (но есть только один из них), MBeta []
для представления всех MBeta
s и MGamma ("", 0)
для представления всех MGamma
s. У вас будет функция для расчета репрезентативного значения из заданного:
let malpha = MAlpha
let mbeta = MBeta []
let mgamma = MGamma ("", 0)
let canonicalize =
function
| MAlpha -> malpha
| MBeta _ -> mbeta
| MGamma _ -> mgamma
let find_first where what =
canonicalize (List.find (fun x -> List.mem (canonicalize x) what) where)
let main () =
let where_to_find = [MGamma ("a", 3); MAlpha; MBeta [3; 4]] in
let what_to_find = [malpha; mbeta] in
try
let found = find_first where_to_find what_to_find
in
if found = malpha then (* what to do *)
else if found = mbeta then (* what to do *)
else (* what to do *)
with Not_found -> (* nothing was there *)
Я написал такой код, и он не так уж плох. В вашем случае это позволяет вам указать параметр what
немного естественным образом. Один недостаток, однако, заключается в том, что вы не можете сопоставлять паттерны с malpha
, mbeta
и mgamma
. Вы должны сравнить их на равенство.
Возможно, вы хотели найти конкретное значение в списке, а не канонизированное значение. Я думаю, что изменения для этого случая должны быть достаточно ясными.
Это также отвечает на вторую часть вашего вопроса. Функция List.find
остановится, как только найдет то, что ищет.
OCaml определяет отношение порядка для всех типов, которые не содержат функциональных значений в них. Если этот встроенный (полиморфный) порядок не делает то, что вы хотите, вы должны определить свой собственный. Вам, безусловно, нужно сделать это, чтобы сравнить значения двух разных типов; но это не то, что вы здесь делаете.
Если в списке нет элемента, который выглядел бы так, как вы сказали, вы хотели, эта версия find_first
вызовет исключение Not_found
. Об этом стоит подумать.