2017-07-04 108 views
0

我從this question得知可以使用模式匹配與記錄。但是,我注意到我在嘗試匹配不同類型的記錄時遇到了問題。含模式匹配記錄的歧義

我在這個例子中的目標是能夠區分不同的記錄。我得到了一個記錄,我不完全確定它是哪種類型,我試圖用模式匹配來解決它。

這裏有一個簡單的例子:

module IceCream = struct 
    type t = { 
    temperature: float; 
    toppings: string list; 
    } 
end 

module Candy = struct 
    type t = { 
    flavour: string; 
    colour: string; 
    volume: int; 
    } 
end 


(* Could be Candy or IceCream *) 
let example = 
    { Candy. 
    flavour = "mint"; 
    colour = "green"; 
    volume = 10 } 

let printFavoriteTreat treat = match treat with 
    | { Candy. 
     flavour = "mint"; 
     colour; 
     volume } -> "It's Candy" 
    | { IceCream. 
     temperature; 
     toppings } -> "It's IceCream" 


let() = printFavoriteTreat example 

當我嘗試建立這個文件,我得到:

Error: The field IceCream.temperature belongs to the record type IceCream.t 
     but a field was expected belonging to the record type Candy.t 

正在做這樣的事情可能嗎?

+0

不同類型的模式匹配是不可能的,除非它們被嵌入到和類型(也稱爲變體類型,代數數據類型,區分聯合)中。 – didierc

回答

3

我給了一個記錄,我不完全確定它是哪種類型,而我試圖用模式匹配來解決它。

這是不可能的。類型只在編譯時才存在,因此在運行時檢查它的類型是不可能的。

換句話說,在一個有效的程序中,你可以在每個表達式上放置一個類型註解(在大多數情況下,你不必這樣做,但是,歸功於類型推斷)。如果你不能這樣做,那麼你應該設計你的程序有不同的方式,比如像其他人所建議的那樣使用sum類型 - 在這種情況下,兩個值將具有相同的類型(在編譯時),但具有不同的構造函數(在運行時)。

1

您正在嘗試匹配不同類型而不使用變體類型。

您正在使用的模塊語法無法提供幫助,因爲模塊只是構造代碼。您可以定義以下類型:

type a = { 
    temperature: float; 
    toppings: string list; 
    } 

type b = { 
    flavour: string; 
    colour: string; 
    volume: int; 
    } 

但結果將是相同的。

消除歧義的方法是使用(未在下面的例子中描述的或聯合型)變體類型:

let printFavoriteTreat treat = match treat with 
    | `A{ Candy. 
     flavour = "mint"; 
     colour; 
     volume } -> "It's Candy" 
    | `B { IceCream. 
     temperature; 
     toppings } -> "It's IceCream" 
;; 

而且

let() = printFavoriteTreat (`A example) 
+0

你可能應該使用\\ Candy而不是\\ A和\\ IceCream而不是\\ B。並解釋爲什麼一個多態變體(+包括'| _ - >「我不知道那個對待」')而不是一個正常的變體。 –

3

由Pierre提供的答案是很大的,但這個例子並不多。 (我一直討厭命名爲ab例子......)

所以,皮埃爾建議,你可以定義你的類型是這樣的:

type ice_cream = { 
    temperature: float; 
    toppings: string 
} 

type candy = { 
    flavor: string; 
    color: string; 
    volume: int 
} 

然後,您可以定義類型treat作爲這兩種類型的variant

type treat = 
| Candy of candy 
| IceCream of ice_cream 

然後,用模式匹配:

let print_favorite_treat = function 
| Candy _ -> print_endline "You love candy!" 
| IceCream _ -> print_endline "You love ice cream!" 
+0

很好,這是使用聯合類型的;) –

+0

這個函數被稱爲'print_favorite_treat'的事實是一個很好的暗示,需要某種'treat'類型。 :) – RichouHunter

+0

啊我希望我可以避免變種,但它看起來像你不能匹配記錄的方式,我試圖,謝謝你的答案:) –