Thoughts on F#

programming

_ Operator

The _ operator is really cool, an periodically trips me up in its usage. I've learned to combine it by using the >> operator. So there's some List.map operations like

List.map (_.Name>>_.ToLowercase()>>_.Trim())

Which isn't short, but I'm already tired of the fun -> ... pattern everywhere I need to spot-process an item.

Railway Oriented Programming

I read about this on the fun and profit website, but haven't found a good spot to apply it. I was trying to implement this pattern in a pipeline that performed repeated transforms on HTML documents, but I don't think I did so very well. The pattern of repeated Result.bind and Result.map was not doing it for me.

I'm also re-considering my opinions on try and failwith for for exception handling. The ability to pattern match Exceptions and wrap Exceptions into Results and Options might address my discomfort with try..catch patterns from OOP languages. It seems really cool to use exception throwing more readily and implement catching at the Domain boundary, instead of passing Results around as if they were Go errors.

Write Your Own Library

The libraries I've been able to interact with that are written specifically for F# are absolutely delightful. Suave has been really delightful to use and configure in particular.

There's some .NET libraries, like Markdig, that've been fine to use, and really easy to nestle into F# modules. But then there's some libraries, like HTML AgilityPack, that feel simply insane to inter-op with.

I may not have enough experience with F# yet, and maybe there's a much more pragmatic way to leverage Objects and mutable structures that I'm not privy to. Until my tastes change, I'd like my libraries and datastructures to act immutably and work really well with chained operations. I'd tried 4 or so different ways of leveraging AgilityPack's Document objects, but did not stop stubbing my toes until I wrapped up my own HTML module that implemented immutable operations on a custom Node type.

I'll probably keep trying this approach of wrapping external libraries in my own "functional-style" libraries going forward.

Editing and Compiling

Years ago, I'd used C# at work. At that time, the only option I had was Visual Studio (not Code) on Windows. I was still pretty green and the .NET stack felt positively impenetrable. This was all during peak OOP megaliths and well before dotnet-core. A large part of my disdain for .NET at the time was this whole forced ecosystem.

To skip the history of something I wasn't around for, I will say things are pretty nice now. I'm making do just fine with nix as my build system and helix as my editor. I've got a devshell with all the language tooling and project dependencies, and it all works really well.

Building with flake-parts

Nuget packages are pulled in and hashed out-of-band. Using deps.json as a lockfile for Nuget packages. We can generate, and re-generate this lockfile using:

dotnet restore --packages out
nix run nixpkgs#nuget-to-json -- out > deps.json
rm -rf out

I collect all my .NET projects within a single mono solution. I then have a singular top-level nix package that builds the entire solution, with all projects included.

{ ... }:
{
  perSystem =
    { pkgs, lib, ... }:
    {
      packages.mono-dotnet = pkgs.buildDotnetModule {
        name = "mono";

        dotnet-sdk = pkgs.dotnetCorePackages.sdk_10_0;
        dotnet-runtime = pkgs.dotnetCorePackages.runtime_10_0;
        buildInputs = [ ];

        nugetDeps = ./../deps.json;

        src = ./..;
        projectFile = "mono.slnx";
      };
    };
}