-
-
Save medigor/256b9b62759109ec87c88ebd8b5270f2 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(* | |
WHAT'S GOING ON HERE?! | |
Sometimes you don't care about a particular type, you're interested in one field only, let's say `EntityId`. | |
Instead of using interface (which isn't even possible if don't own a type), | |
we can do structural typing in F# using SRTP and Active Patterns. | |
Active patterns are not required for this, but they do make code much easier to use. | |
*) | |
// So we have 2 types with field `EntityId: string`: | |
type Test = | |
{ EntityId: string } | |
type Test2 = | |
{ EntityId: string | |
Name: string | |
Length: int } | |
// First we define active pattern for detecting | |
// whether this type has this field or not: | |
let inline (|HasEntityId|) x = | |
fun () -> (^a : (member EntityId: string) x) // as you can see, SRTP syntax is hardly comfortable to use | |
// Then we define function for retrieving this field | |
let inline entityId (HasEntityId f) = f() | |
// Another AP, this time for detecting `Name: string`: | |
let inline (|HasName|) n = | |
fun () -> (^a : (member Name: string) n) | |
// and function for getting the name: | |
let inline name (HasName f) = f() | |
// Now here's the beauty of it: we can combine them! | |
let inline printNameAndId (HasName n & HasEntityId id) = sprintf "name %s id %s" (n()) (id()) | |
// Watching it in action: | |
let test1 = { EntityId = "123" } | |
let test2 = {Test2.EntityId = "123"; Name = "123"; Length = 2} | |
// Works both with Test and Test2 types since both have `EntityId` field | |
let a = entityId test1 | |
let b = entityId test2 | |
let c = name test2 | |
let d = printNameAndId test2 | |
// *Compile* error when using type without required fields: | |
let error = printNameAndId test1 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment