F# 使用可区分联合的基类型

F# Use base type of discriminated union

我正在学习 F#,但在尝试使用可区分联合时遇到困难。我有一个简单的案例,我试图在一个简单的 Map 类型的可区分联合上使用 Map.map,但它说存在类型不匹配。我基本上只是想将价格类型用作 Map

这是一个简化的例子:

type Prices = Prices of Map<string, int>

let GetSalePrice (prices: Prices) = prices |> Map.map (fun k v -> (k, v * 2))

给我这个错误:

/Users/luke/code/chronos/Chronos.Mining/Chronos.Mining.Actors/Untitled-1(22,47): error FS0001: Type mismatch. Expecting a
    'Prices -> 'a'    
but given a
    'Map<'b,'c> -> Map<'b,'d>'    
The type 'Prices' does not match the type 'Map<'a,'b>'

考虑到我在 map 函数中所做的只是返回值 * 2,我不明白为什么会出现此错误。

您不能“Prices用作Map”,因为Prices不是一个Map。按照您定义它的方式,Prices 是一种不同的类型,与 Map 完全不同,但它 包含 [=19] 的一个实例=]里面。

如果这确实是您的意思,那么为了从 Prices 值中获取 Map,您需要对其进行模式匹配。像这样:

let GetSalePrice (Prices theMap) = theMap |> Map.map ...

哇,这是怎么回事? Prices theMapprices: Prices 有何不同?为什么我们将类型名称放在参数前面而不是通过冒号放在后面? F# 中的类型不是这样表示的吗?

您可能有点困惑,因为您对类型及其构造函数使用相同的名称 Prices。为了解决这个问题,让我像这样重新定义你的类型:

type PricesType = PricesCtor of Map<string, int>

现在函数看起来像:

let GetSalePrice (PricesCtor theMap) = theMap |> Map.map ...

所以你看,这不是我们放在参数前面的类型。它是构造函数。这个声明 - (PricesCtor theMap) - 告诉编译器我们期待一个类型为 PricesType 的参数(因为那是 PricesCtor 所属的地方),当我们得到这个参数时,它应该被解包,其中包含的地图应命名为 theMap.

整个过程称为"pattern matching"。在这里,我们在构造函数 PricesCtor.

上进行匹配

另一方面,您的原始函数仅指定了参数的类型。使用我的新类型定义,我可能会像这样编写您的原始函数:

let GetSalePrice (prices: PricesType) = prices |> Map.map ...

在这里,我们指定我们的参数应具有类型 PricesType,但随后我们试图将其用作 Map.map 的参数,它需要类型为 [=37= 的参数].难怪类型不匹配!


模式匹配也不必在参数声明中。您可以在代码中的任何位置进行模式匹配。为此,请使用 match 关键字。这就是您的函数可以这样写的方式:

let GetSalePrice prices =
    match prices with
    | PricesCtor theMap -> theMap |> Map.map ...

只要您的类型具有多个构造函数,match 关键字就变得很重要。例如:

type PricesType = PricesAsAMap of Map<string, int> | SinglePrice as int

在这种情况下,如果您在参数声明中指定模式:

let GetSalePrice (PricesAsAMap theMap) = ...

编译器会警告您模式匹配不完整。实际上,您的函数知道在给定 SinglePrice 值时该做什么,但是在给定 ConstantPrice 时它应该做什么?你还没有定义它,所以编译器会抱怨。

此设置是使用 match 关键字的场合:

let GetSalePrice prices = 
    match prices with
    | PricesAsAMap theMap -> theMap |> Map.map ...
    | SinglePrice p -> "single item", p