FSharpPrelude
This class library contains a heterogeneous, loosely organized collection of functions and datatypes, the overarching design principles being:
- These definitions and utilities could conceivably be used in any F# program.
- We attempt to maintain a clear delineation of implementations:
- purely functional
- "mostly" functional
- imperative/object programming. Note Although we do use objects we try to avoid an "object-oriented" approach.
- Thread-safe vs. unsafe
- Synchronous vs. async
- Managed vs. unmanaged. Note For performance reasons many implementations use unmanaged memory access. I am trying to do all of this in F#, awkward as it is. There is a separate Unsafe module that tries to clean this up.
- For a given interface, we try to offer multiple implementations using the above
Outline
- Prelude
- Graph
- Collections
- Math
Some major open design questions I am still thinking about
.NET interfaces vs record-type-of-signatures
In recent years it has become somewhat fashionable for F# programmers to eschew .NET interfaces, as in the following two types:
type IMyInterface =
abstract member Property : int
abstract member InstanceMethod : int -> int
type MyInterfaceRecord = {
Property : int
InstanceMethod : int -> int
}
Semantically these types are basically equivalent, with F#'s object expressions making that equivalency more direct:
let myInterfaceInstance : IMyInterface = {
new IMyInterface with
member x.Property = 5
member x.InstanceMethod = fun x -> x*x
}
let myRecordInterfaceInstance : MyInterfaceRecord = {
Property = 5;
InstanceMethod = fun x -> x*x
}
The MyInterfaceRecord
is more idiomatically functional and easier to deal
with in an ordinary F# program. But the two types are not at all equivalent
for the .NET runtime. Specifically, IMyInterface
exists as a first-class
citizen in IL and can be readily consumed by C# programs, whereas
MyInterfaceRecord
is an instance of a very complicated class in the F#
backend library.
This leads me to suspect that using .NET interfaces is a better choice for performance, and that the syntactic advantages of record interfaces are minimal given that object expressions are largely equivalent. However, at a core level F# is less well-suited for programming with interfaces than C#, with programs often requiring awkward casts and excessive boilerplate code. So there may be disadvantages to using this approach. I will unfortunately need to benchmark this to see what the details actually are :(