'is there a way to handle standard fields in this DU, in F#?
I have some quite ugly code here:
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
And there are many common fields across all DU types that I need to extract like this; and they have, of course, a lot of different fields as well.
Is there a nicer way to extract the common fields? The DateTime is separated from the underlying type, but there are also common fields across all the types.
How could this be rewritten in a nicer way?
Solution 1:[1]
As Fyodor suggests, this can be refactored as:
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
And if you want to refactor even further, you could do something like this:
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 ()
Solution 2:[2]
I would recommend to do what Brian suggests and refactor the code so that you have a record with Timestamp and separate discriminated union with event details.
However, if you really want to keep your representation as a union with duplicate items, you can simplify the logic somewhat by using an active pattern that recognizes different types of events based on what other information they contain - so all Zone events would be recognized as one thing. For simplicity, here is an example using just the two latter types of events:
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)
Now you can write logic only by considering three (two in my example) cases:
let getTimeStamp e =
match e with
| FairPriceEvent(ts, _)
| LiquidityEvent(ts, _) -> ts
let getInterval e =
match e with
| FairPriceEvent(_, l)
| LiquidityEvent(_, l) -> l.Interval
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | Tomas Petricek |
