使用模式匹配F#

时间:2020-08-26 04:24:59

标签: types syntax f# pattern-matching

是否可以内联使用Type Test PatternRecord Pattern

我可以毫无问题地制作记录模式:

let getName3 (a:A) =
  match a with
  | { name = name } -> name

这是一个完全有效的代码:

type IA =
  abstract ID: string

type A =
  { id: string
    name: string }
  interface IA with
    member this.ID = this.id

let getName (a: IA) =
  match a with
  | :? A as a -> a.name
  | _ -> ""

getName
  { id = "1234"
    name = "andrew" }

// val getName : a:IA -> string
// val it : string = "andrew"

这就是我在说的:

let getName2 (a: IA) =
  match a with
  | :? A ({name = name}) as a -> name // Type Test Pattern with Record Pattern inline, maybe even still use binding (as a)
  | _ -> ""

更新

我之前的示例太简单了,请改用以下示例:

type IA =
  abstract ID: string

type Stage =
  | FirstStep
  | SecondStep
  
type A =
  { id: string
    name: string option
    stage: Stage
  }
  interface IA with
    member this.ID = this.id

// This is a "nested" pattern inline, I match two Option with one match 
let tryGetName (a: A option) =
  match a with
  | Some { name = (Some name) } -> Some name
  | _ -> None

// This is a more involved nested pattern inline
let tryGetStageAndName (a: A option) =
  match a with
  | Some { name = (Some name); stage = stage } -> Some (stage, name)
  | _ -> None

// This is the syntax I'm looking for:
let tryGetStageAndName2 (a: IA option) =
  match a with
// notice Some (:? A as a) -> is perfectly valid
  | Some (:? A ({ name = (Some name); stage = stage }) -> Some (stage, name)
  | _ -> None

我也想澄清一下,我的问题是关于F#语法的问题,而不是即席场景或围绕特定type A的拳击,因为我们可以进行嵌套的内联模式,有没有办法在Type之后做模式测试模式?

3 个答案:

答案 0 :(得分:3)

您可以使用活动模式。我们的想法是将类型测试模式转换为其他模式,其中强制转换值将参与其中,因此我们可以将“记录模式”嵌套到其中。

代码为:

let (|IsA|_|) (a: IA) =
    match a with
    | :? A as a -> Some a
    | _ -> None

let getName2 (a: IA) =
  match a with
  | IsA {name = name} -> name
  | _ -> ""

答案 1 :(得分:0)

我认为Nghia Bui提出了一个很好的解决方案。我只是想补充一点,您可能想使活动模式通用,以处理更多情况。我将活动模式的大小写重命名为Unbox,这可能并不完全准确。无论如何,请参见以下示例:

type IA =
  abstract ID: string

type A =
  { id: string
    name: string }
  interface IA with
    member this.ID = this.id

type B =
  { id: string
    name: string
    email: string }
  interface IA with
    member this.ID = this.id

let inline (|Unbox|_|)<'T when 'T :> IA> (a: IA) =
    match a with
    | :? 'T as a -> Some a
    | _ -> None

let getName (a: IA) =
  match a with
  | Unbox {A.name = name} -> name
  | Unbox {B.name = name} -> name
  | _ -> ""

getName {id = "123"; name = "A name"}
getName {id = "567"; name = "B name"; email = "abc@123.com"}

答案 2 :(得分:0)

这是fslang-uggestions中的建议:

https://github.com/fsharp/fslang-suggestions/issues/830

此语法尚不存在

相关问题