Last active
June 27, 2024 18:57
-
-
Save Savelenko/e508570fa8ef9dc0b4e8f2f98b1aff59 to your computer and use it in GitHub Desktop.
F# existential types
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 characters
// The engine interface and helpers | |
type IEngine<'a,'b> = | |
abstract member Capacity : int // Does not depend on 'a or 'b; just an example | |
// Some other stuff here possible depending on 'a and 'b | |
/// A function which works on any engine polymorphically and returns a result of type 'r'. Needed because | |
/// F# does not support higher-ranked types (not the same as HKT!) in regular functions. This does work in members. | |
type EngineFunction<'r> = | |
abstract member Apply : IEngine<'a,'b> -> 'r | |
/// Hides type parameters of an engine. "Existential types" because "there is (exists) a type passed as a parameter to | |
/// IEngine, but I won't tell you which". | |
type ExistsEngine = | |
abstract member Elim : EngineFunction<'r> -> 'r | |
// Helper for introduction. Use this to "unify" engines of different types. | |
let existsEngine engine = { new ExistsEngine with | |
member _.Elim f = f.Apply engine | |
} | |
// Helper for elimination. Use this to do something with any engine. | |
let elimExistsEngine f (engine : ExistsEngine) = engine.Elim f | |
// Example | |
// A string, int engine | |
let engine1 = { new IEngine<string,int> with | |
member _.Capacity = 3 | |
} | |
// A int, string, so different type from engine1 | |
let engine2 = { new IEngine<int, string> with | |
member _.Capacity = 5 | |
} | |
// A list with both engines, in a way | |
let bothEngines = [existsEngine engine1; existsEngine engine2] // List<ExistsEngine> | |
// Corresponds to the function which determines the capacity of any engine. | |
let capacity = { new EngineFunction<int> with | |
member _.Apply engine = engine.Capacity | |
} | |
// Maximum capacity of all engines, regardless of their type | |
let maxCapacity = bothEngines |> List.map (elimExistsEngine capacity) |> List.max // int |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment