2017-07-04 107 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

啊我希望我可以避免变种,但它看起来像你不能匹配记录的方式,我试图,谢谢你的答案:) –