OCaml: найти значение определенного типа - PullRequest
2 голосов
/ 24 сентября 2011

У меня есть список некоторых значений, где мне нужно выяснить, какой тип значения первый:

type my_types =
    | MAlpha
    | MBeta of int list
    | MGamma of string * int

let find_first where what =
    List.iter ( fun m ->
        | MAlpha ->
            (* iterate frough "what" to find if it was asked to look and return it if it was *)
        | (* do the same for all other types *)
    ) where;
;;

let main =
    let where_to_find = [MGamma, MAlpha, MBeta] in
    let what_to_find = [MAlpha, MBeta] in
    (match (first_found where_to_find what_to_find) with
    | MAlpha ->
        (* should return this *)
    )
;;

Есть ли способ сделать это, не касаясь всех типов MyType в пределах find_first - возможно ли сравнить типы двух значений? Спасибо.

Ответы [ 2 ]

4 голосов
/ 24 сентября 2011

Код, который вы опубликовали, не будет компилироваться, но я думаю, что вы ищете следующую информацию:

  1. Можно написать так называемые или-паттерны, как, например, в (function MAlpha | MBeta _ -> ...).

  2. Но образцы не первоклассные граждане. Вы не можете построить шаблон из списка (и, кстати, [MGamma, MAlpha, MBeta] - это одна из вещей, которая не компилируется в вашем вопросе), а также вы не можете передать шаблон в качестве аргумента функции.

  3. Однако вы можете построить и передать функцию, которая соответствует шаблону, поэтому, если вы хотите изменить свою функцию find_first, чтобы взять функцию вместо списка для what, она будет удобнее в использовании.

3 голосов
/ 24 сентября 2011

Еще один способ взглянуть на это состоит в том, что у вас есть отношение эквивалентности для вашего типа; то есть, у вас есть несколько мест, где вы хотите обрабатывать все 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. Об этом стоит подумать.

...