2

鉴于以下情况:

type IFruit = interface end

type Avocado = { color : string; age : int } interface IFruit

let (|AvocadoTexture|) (a : Avocado) = if a.age < 7 then "firm" else "mushy"

...为什么会这样:

let texture (f : IFruit) =
    match f with
    | :? Avocado as a -> if a.age < 7 then "firm" else "mushy"
    | _ -> String.Empty

...但不是这个?

let texture (fruit : IFruit) =
    match fruit with
    | AvocadoTexture t -> t    // "The type IFruit does not match the type Avocado"
    | _ -> String.Empty
4

2 回答 2

6

fruit可能是 any IFruit,但AvocadoTextureActive Pattern 只接受特定的实现Avocado,根据a. 如果您希望活动模式接受 any IFruit,但只返回一个有用的值 an Avocado,您可以将其设为partial

let (|AvocadoTexture|_|) (f : IFruit) =
    match f with
    | :? Avocado as a ->
        if a.age < 7 then "firm" else "mushy"
        |> Some
    | _ -> None

现在您的texture功能可以按您的意愿工作:

let texture (fruit : IFruit) =
    match fruit with
    | AvocadoTexture t -> t
    | _ -> String.Empty
于 2017-05-16T01:21:53.033 回答
2

请记住,有部分活动模式和活动模式。活动模式最多有 7 个标签,可以具体匹配某些东西。这两种形式都很有用。

如果您希望编译器在您决定需要一个额外的案例之后,告诉您您错过处理案例的所有地方,那么活动模式会更好。如果您想对其更加严格,可以将编译器配置为将其标记为错误而不是警告。

open System

type IFruit = interface end

type Avocado = 
  { color : string; age : int } 
  interface IFruit
  static member tryFromIFruit(x:IFruit) = 
    match x with
    | :? Avocado -> Some(x:?>Avocado)
    | _ -> None

let (|Firm|Mushy|) (a : Avocado) = if a.age < 7 then Firm else Mushy

let texture (fruit : IFruit) =
    match fruit |> Avocado.tryFromIFruit with  // we're not sure if it's an Avocado.
    | Some(Firm) -> "firm"                     // use Some(SomethingElse()) when you want to collapse an extra layer of "match" statements.
    | Some(Mushy) -> "mushy"
    | None -> ""

texture ( { color = "green"; age = 4 } :> IFruit)

文档:https ://docs.microsoft.com/en-us/dotnet/articles/fsharp/language-reference/active-patterns

于 2017-05-16T01:47:50.063 回答