2011-07-13 55 views
3

我有訪問記錄,過濾型和名單後

type my_sum = {a : type_a}/{b : type_b} 
mylist = [{field_only_in_a = "test"} : type_a,{haha=3 ; fsd=4} : type_b] 

名單我想這樣做:

result = List.find(a -> match a with 
             | {a = _} -> true 
             | _ -> false 
            end, 
           mylist) 
if Option.is_some(result) then 
    Option.some(Option.get(result).field_only_in_a) 
else 
    Option.none 

就像你所看到的,發現後我一定要得到的東西type_a但編譯時,我得到的是:

Record has type 
{ a : type_a }/{ b : type_b } but field access expected it to have type 
{ field_only_in_a: 'a; 'r.a } 
Hint: 
    You tried to access a sum type with several cases as a record. 

我怎麼能說給compilator,我有分機只有一種類型的總和類型,我有很好的類型來訪問記錄......?

回答

4

那麼,你不能真正告知編譯器,只有一個子類型將存在於列表中......但是你可以明確地創建一個只有這個子類型的列表。其實,你正在尋找的是List.find_map,它找到了符合特定標準的第一個元素並將其映射(您使用該映射從my_sum投影到其案例type_a)。下面是一個完全運行的代碼(編譯自身):

type type_a = {fld_a : string} 
type type_b = {fld_b : int} 
type my_sum = {a : type_a}/{b : type_b} 

mylist = [{a = {fld_a = "test"}}, {b = {fld_b = 10}}] : list(my_sum) 

get_first_a(l : list(my_sum)) : option(type_a) = 
    List.find_map(
    (el -> match el 
      | ~{a} -> some(a) 
      | _ -> none 
    ), l) 

_ = prerr("First a-typed element of {mylist} is {get_first_a(mylist)}\n") 

如果有在STDLIB沒有List.find_map功能仍然會有一噸的方式來做到這一點。可能最簡單的方法是使用List.filter_map獲得list(type_a),然後用List.head_opt得到它的頭。