Last active
January 4, 2025 05:27
-
-
Save atsapura/fd9d7aa26e337eaa2f7f04d6cbb58ef6 to your computer and use it in GitHub Desktop.
Revisions
-
atsapura revised this gist
Jun 6, 2019 . 1 changed file with 5 additions and 1 deletion.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -35,12 +35,16 @@ Active patterns are not required for this, but they do make code much easier to 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 -
atsapura revised this gist
Jun 6, 2019 . 1 changed file with 25 additions and 3 deletions.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -1,4 +1,13 @@ (* 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 } @@ -7,18 +16,31 @@ 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 test2 = {Test2.EntityId = "123"; Name = "123"; Length = 2} // Works both with Test and Test2 types since both have `EntityId` field let a = entityId { EntityId = "123" } let b = entityId test2 let c = name test2 let d = printNameAndId test2 -
atsapura created this gist
Jun 3, 2019 .There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,24 @@ type Test = { EntityId: string } type Test2 = { EntityId: string Name: string Length: int } let inline (|HasEntityId|) x = fun () -> (^a : (member EntityId: string) x) let inline entityId (HasEntityId f) = f() let inline (|HasName|) n = fun () -> (^a : (member Name: string) n) let inline name (HasName f) = f() let inline test2f (HasName n & HasEntityId id) = sprintf "name %s id %s" (n()) (id()) let test2 = {Test2.EntityId = "123"; Name = "123"; Length = 2} let a = entityId { EntityId = "123" } let b = entityId test2 let c = name test2 let d = test2f test2