Luk*_*keP 3 f# discriminated-union
我正在学习 F# 并努力尝试使用受歧视的联合。我有一个简单的案例,我试图Map.map在类型 Map 的简单可区分联合上使用,但它说存在类型不匹配。我基本上只是想使用类型价格作为地图
这是一个简化的示例:
type Prices = Prices of Map<string, int>
let GetSalePrice (prices: Prices) = prices |> Map.map (fun k v -> (k, v * 2))
Run Code Online (Sandbox Code Playgroud)
给我这个错误:
/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>'
Run Code Online (Sandbox Code Playgroud)
鉴于我在 map 函数中所做的一切都是返回值 * 2 我不明白为什么我会收到这个错误。
你不能“使用Prices的Map”,因为Prices是不是一个Map。您定义它的方式Prices是一种不同的类型,与 a 完全不同Map,但它在其中包含a 的实例Map。
如果这确实是您的意思,那么为了得到Map一个Prices值,您需要对其进行模式匹配。像这样:
let GetSalePrice (Prices theMap) = theMap |> Map.map ...
Run Code Online (Sandbox Code Playgroud)
哇,这是怎么回事?如何Prices theMap不同prices: Prices?为什么我们将类型名称放在参数前面而不是通过冒号放在后面?这不是 F# 中类型的表示方式吗?
您可能会有些困惑,因为您Prices对类型及其构造函数使用了相同的名称。为了解决这个问题,让我像这样重新定义你的类型:
type PricesType = PricesCtor of Map<string, int>
Run Code Online (Sandbox Code Playgroud)
现在函数看起来像:
let GetSalePrice (PricesCtor theMap) = theMap |> Map.map ...
Run Code Online (Sandbox Code Playgroud)
所以你看,它不是我们放在参数前面的类型。它是构造函数。这个声明 - (PricesCtor theMap)- 告诉编译器我们期待一个类型的参数PricesType(因为它是PricesCtor属于哪里的),当我们得到这个参数时,它应该被解包,其中包含的映射应该被命名为theMap。
这整个过程称为“模式匹配”。在这里,我们在构造函数上进行匹配PricesCtor。
另一方面,您的原始函数仅指定参数的类型。使用我的新类型定义,我可能会像这样编写原始函数:
let GetSalePrice (prices: PricesType) = prices |> Map.map ...
Run Code Online (Sandbox Code Playgroud)
在这里,我们指定我们的参数应该有 type PricesType,但是我们试图将它用作 的参数Map.map,它需要一个 type 的参数Map<_,_>。难怪有类型不匹配!
模式匹配也不必出现在参数声明中。您可以在代码中的任何位置进行模式匹配。为此,请使用match关键字。这就是您的函数可以这样编写的方式:
let GetSalePrice prices =
match prices with
| PricesCtor theMap -> theMap |> Map.map ...
Run Code Online (Sandbox Code Playgroud)
match只要您的类型具有多个构造函数,关键字就变得很重要。例如:
type PricesType = PricesAsAMap of Map<string, int> | SinglePrice as int
Run Code Online (Sandbox Code Playgroud)
在这种情况下,如果您在参数声明中指定模式:
let GetSalePrice (PricesAsAMap theMap) = ...
Run Code Online (Sandbox Code Playgroud)
编译器会警告您模式匹配不完整。确实,您的函数知道在给定SinglePrice值时该做什么,但是当给定 a 时它应该做什么ConstantPrice?你还没有定义它,所以编译器会抱怨。
此设置是使用match关键字的场合:
let GetSalePrice prices =
match prices with
| PricesAsAMap theMap -> theMap |> Map.map ...
| SinglePrice p -> "single item", p
Run Code Online (Sandbox Code Playgroud)