简体   繁体   English

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

[英]F# Use base type of discriminated union

I'm learning F# and struggling trying to use discriminated unions.我正在学习 F# 并努力尝试使用受歧视的工会。 I have a simple case where I'm trying to use Map.map on a simple discriminated union of the type Map but its saying there is a type mismatch.我有一个简单的案例,我试图在Map.map类型的简单区分联合上使用 Map.map 但它说存在类型不匹配。 I'm basically just trying to use the type Prices as a Map我基本上只是想将价格类型用作 Map

Here is a simplified example:这是一个简化的示例:

type Prices = Prices of Map<string, int>

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

Gives me this error:给我这个错误:

/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>'

Given that all I'm doing in the map function is returning the value * 2 I don't understand why I'm getting this error.鉴于我在 map function 中所做的一切都返回值 * 2 我不明白为什么会出现此错误。

You cannot " use Prices as a Map ", because Prices is not a Map .您不能“Prices用作Map ”,因为Prices不是Map The way you have defined it, Prices is a different type, not at all the same as a Map , but it contains an instance of a Map inside it.您定义它的方式, Prices是一种不同的类型,与Map ,但它包含一个Map的实例。

If this is indeed what you meant, then in order to get the Map out of a Prices value, you need to pattern-match on it.如果这确实是您的意思,那么为了使Map脱离Prices值,您需要对其进行模式匹配。 Like this:像这样:

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

Whoa, what's going on here?哇,这是怎么回事? How is Prices theMap different from prices: Prices ? Prices theMap与价格有何不同prices: Prices Why are we putting the type name in front of the parameter rather than behind it via a colon?为什么我们将类型名称放在参数前面而不是通过冒号放在参数后面? Isn't that how types are denoted in F#? F# 中的类型不是这样表示的吗?

You may have a bit of a confusion because you're using the same name Prices for both the type and its constructor.您可能会有些困惑,因为您对类型及其构造函数使用了相同的名称Prices To clear this up, let me redefine your type like this:为了澄清这一点,让我重新定义你的类型,如下所示:

type PricesType = PricesCtor of Map<string, int>

Now the function would look like:现在 function 看起来像:

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

So you see, it's not the type that we're putting in front of the parameter.所以你看,这不是我们放在参数前面的类型。 It's the constructor.它是构造函数。 And this declaration - (PricesCtor theMap) - tells the compiler that we're expecting a parameter of type PricesType (because that's where PricesCtor belongs), and when we get this parameter, it should be unwrapped, and the map contained within should be named theMap .这个声明 - (PricesCtor theMap) - 告诉编译器我们期待一个价格类型的参数(因为那是PricesType所属的PricesCtor ),当我们得到这个参数时,它应该被解包,并且其中包含的 map 应该被命名theMap

This whole process is called "pattern matching".这整个过程称为“模式匹配”。 Here, we're matching on the constructor PricesCtor .在这里,我们在构造函数PricesCtor上进行匹配。


Your original function, on the other hand, merely specified the type of the parameter.另一方面,您原来的 function 只是指定了参数的类型。 With my new type definition I might write your original function like this:使用我的新类型定义,我可能会像这样编写您的原始 function:

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

Here, we specify that our parameter should have type PricesType , but then we're trying to use it as an argument for Map.map , which expects a parameter of type Map<_,_> .在这里,我们指定我们的参数应该具有价格类型,但随后我们尝试将其用作PricesTypeMap.map ,它需要一个类型为Map<_,_>的参数。 No wonder there is a type mismatch!难怪有类型不匹配!


Pattern matching doesn't have to be in the parameter declaration either.模式匹配也不必在参数声明中。 You can pattern-match anywhere in the code.您可以在代码中的任何位置进行模式匹配。 To do that, use the match keyword.为此,请使用match关键字。 This is how your function may be written that way:这就是您的 function 可以这样写的方式:

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

The match keyword becomes significant as soon as your type has more than one constructor.一旦你的类型有多个构造函数, match关键字就变得很重要。 For example:例如:

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

In this case, if you specify the pattern in the parameter declaration:在这种情况下,如果您在参数声明中指定模式:

let GetSalePrice (PricesAsAMap theMap) = ...

the compiler will warn you that the pattern match is incomplete .编译器会警告您模式匹配不完整 Indeed, your function knows what to do when given a SinglePrice value, but what should it do when given a ConstantPrice ?确实,您的 function 知道在给定SinglePrice值时该怎么做,但是在给定ConstantPrice时应该怎么做? You haven't defined that, so the compiler will complain.你还没有定义,所以编译器会抱怨。

This setup is an occasion to use the match keyword:此设置是使用match关键字的场合:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM