有没有办法在 F# 中处理这个 DU 中的标准字段?

is there a way to handle standard fields in this DU, in F#?

我这里有一些非常难看的代码:

type AnalysisEvent =
    | ZoneStart             of DateTime * ConsolidationZone
    | ZoneEndExitHigh       of DateTime * ConsolidationZone
    | ZoneEndExitLow        of DateTime * ConsolidationZone
    | ZoneContraction       of DateTime * ConsolidationZone
    | ZoneExpansion         of DateTime * ConsolidationZone
    | FairPriceCrossHigh    of DateTime * FairPriceLine
    | FairPriceCrossLow     of DateTime * FairPriceLine
    | LiquidityLineCreated  of DateTime * LiquidityLine
    | LiquidityLineReached  of DateTime * LiquidityLine

    member this.GetTimestamp () =
        match this with
        | ZoneStart             (ts, _) -> ts
        | ZoneEndExitHigh       (ts, _) -> ts
        | ZoneEndExitLow        (ts, _) -> ts
        | ZoneContraction       (ts, _) -> ts
        | ZoneExpansion         (ts, _) -> ts
        | FairPriceCrossHigh    (ts, _) -> ts
        | FairPriceCrossLow     (ts, _) -> ts
        | LiquidityLineCreated  (ts, _) -> ts
        | LiquidityLineReached  (ts, _) -> ts

    member this.GetInterval () =
        match this with
        | ZoneStart             (_, x) -> x.Interval
        | ZoneEndExitHigh       (_, x) -> x.Interval
        | ZoneEndExitLow        (_, x) -> x.Interval
        | ZoneContraction       (_, x) -> x.Interval
        | ZoneExpansion         (_, x) -> x.Interval
        | FairPriceCrossHigh    (_, x) -> x.Interval
        | FairPriceCrossLow     (_, x) -> x.Interval
        | LiquidityLineCreated  (_, x) -> x.Interval
        | LiquidityLineReached  (_, x) -> x.Interval

我需要像这样提取所有 DU 类型中的许多公共字段;当然,他们也有很多不同的领域。

有没有更好的方法来提取公共字段? DateTime 与基础类型分开,但所有类型也有公共字段。

如何以更好的方式重写它?

正如 Fyodor 所建议的,这可以重构为:

type AnalysisEventType =
    | ZoneStart             of ConsolidationZone
    | ZoneEndExitHigh       of ConsolidationZone
    | ZoneEndExitLow        of ConsolidationZone
    | ZoneContraction       of ConsolidationZone
    | ZoneExpansion         of ConsolidationZone
    | FairPriceCrossHigh    of FairPriceLine
    | FairPriceCrossLow     of FairPriceLine
    | LiquidityLineCreated  of LiquidityLine
    | LiquidityLineReached  of LiquidityLine

type AnalysisEvent =
    {
        EventType : AnalysisEventType
        Timestamp : DateTime
    }

    member this.GetTimestamp () =   // you probably don't even need this any more
        this.Timestamp

    member this.GetInterval () =
        match this.EventType with
        | ZoneStart             x
        | ZoneEndExitHigh       x
        | ZoneEndExitLow        x
        | ZoneContraction       x
        | ZoneExpansion         x -> x.Interval
        | FairPriceCrossHigh    x
        | FairPriceCrossLow     x -> x.Interval
        | LiquidityLineCreated  x
        | LiquidityLineReached  x -> x.Interval

如果你想进一步重构,你可以这样做:

type ConsolidationZoneEventType =
    | Start
    | EndExitHigh
    | EndExitLow
    | Contraction
    | Expansion

type FairPriceEventType =
    | CrossHigh
    | CrossLow

type LiquidityLineEventType =
    | Created
    | Reached

type AnalysisEventType =
    | ConsolidationZoneEventType of ConsolidationZoneEventType * ConsolidationZone
    | FairPriceEventType of FairPriceEventType * FairPriceLine
    | LiquidityLineEventType of LiquidityLineEventType * LiquidityLine

    member this.GetInterval () =
        match this with
        | ConsolidationZoneEventType (_, x) -> x.Interval
        | FairPriceEventType (_, x) -> x.Interval
        | LiquidityLineEventType (_, x) -> x.Interval

type AnalysisEvent =
    {
        EventType : AnalysisEventType
        Timestamp : DateTime
    }

    member this.GetTimestamp () =
        this.Timestamp

    member this.GetInterval () =
        this.EventType.GetInterval ()

我建议按照 Brian 的建议进行操作并重构代码,以便您拥有 Timestamp 的记录,并使用事件详细信息单独区分并集。

但是,如果您真的想将您的表示保留为与重复项目的并集,您可以通过使用一种活动模式来稍微简化逻辑,该模式根据事件包含的其他信息识别不同类型的事件 - 所以所有 Zone 事件将被识别为一件事。为简单起见,这里是一个仅使用后两种事件类型的示例:

let (|FairPriceEvent|LiquidityEvent|) e =
  match e with 
  | FairPriceCrossHigh(ts, l) | FairPriceCrossLow(ts, l) -> 
      FairPriceEvent(ts, l)
  | LiquidityLineCreated(ts, l) | LiquidityLineReached (ts, l) -> 
      LiquidityEvent(ts, l)

现在你可以只考虑三种(在我的例子中是两种)情况来编写逻辑:

let getTimeStamp e =
  match e with 
  | FairPriceEvent(ts, _)
  | LiquidityEvent(ts, _) -> ts

let getInterval e =
  match e with 
  | FairPriceEvent(_, l)
  | LiquidityEvent(_, l) -> l.Interval