F# library development guidelines

Are there any good tutorials/guidelines for developing F# libraries? I’m considering porting some of my open-source Elm packages such as elm-geometry to F#, but had a few questions like:

  • What are the currently recommended ways to set up a library project? Some combination of dotnet new, Paket, FAKE…?
  • Are there good ways to publish for multiple .NET versions? I’d love to just stick to .NET 5 (or 6 once it’s out), but I’ll likely have to at least attempt to also build for .NET Framework 4.7. Is this possible using multiple build targets in FAKE or something?
  • Are the Microsoft F# component design guidelines the best general source for library design best practices or are there others I should be checking out?
  • One specific API design question - is it considered best practice to expose functions as both module-level functions and member methods on types? (So that you could for example write both Vector3d.plus v1 v2 or v1.Plus(v2)…)

I hope these questions make sense - I’m still trying to orient myself to the F# ecosystem in general so I may have made some bad assumptions.

  1. Simplest is using standard dotnet packaging which you get with dotnet new or new projects from IDEs.
  2. Target netstandard2.0. It gives a very good set of APIs and has very wide compatibility, including netframework4.7.
  3. That’s a very good guide!
  4. For the plus operation in particular I would define static member (+) (x:Vector3D,y:Vector3D) to allow for use of the addition operator. (.Net will have static interface methods which may in the future shift the preferred approach to interface IAddable<Vector3D> with static member Add(x,y) = ....) In general it depends on the method. I use functions or instance methods depending on which is more natural and v1.Plus(v2) is an example where I wouldn’t use the instance method as the asymmetry doesn’t fit the operation. For functions, you can implement curried or tupled functions - Plus v1 v2 or Plus(v1,v2) - but note that if you use curried functions you restrict consumption to F#. I personally use curried functions only if 1. consumers will be F# only, and 2. there is a natural curried order with one input that is more varying than the other.
1 Like

Thanks @charlesroddie, that’s very helpful! Targeting netstandard2.0 does seem like good advice. And good point on adding a + operator - I should have picked a better example :slightly_smiling_face:

I’ll probably start with an F#-centric API, and then look at improving support for C# etc. if there’s a need.