DEV Community

Cover image for F# is Pretty Cool
Ben Lovy
Ben Lovy

Posted on

F# is Pretty Cool

I decided to tackle this year's Advent of Code in F#. It's not only my first time using this language, it's my first time ever using .NET. I don't know anything about using the Common Language Infrastructure at all. I was expecting a rough, slow start as I got used to a brand new environment, and I'd be able to write about the process as I learn how to unstick myself.

Hasn't happened. Turns out F# is great, highly easy to use, and I haven't gotten stuck. In fact, it's probably the quickest I've made it from "brand-new language" to "solved an AoC-type problem", ever. So I'm just going to write that post instead.

I've certainly gotten stuck on the problems, and I'm not necessarily pleased with my implementations so far - all could be optimized - but my issues have nothing to do with F#. The documentation is thorough, and I'm generally a single Google away from the .NET function I'm looking for. Lots of documentation for C# will apply too if you can't find anything for F# specifically - my only trouble is not knowing any C# either, but it's Java-enough to follow along!

Now, to be fair, I don't think you'd have the same experience if it were your first MLish language. But having even just a very little bit myself in Haskell and OCaml I found nothing surprising here.

Almost everything I've needed I've found right on the Tour of F# and the Language Reference covered everything else.

There's also this great website, downloadable as an offline ebook: F# for Fun and Profit.

Some things I like:

Pipes:

util.applyClaims fileName
|> Seq.filter (fun el -> List.length el > 1)
|> Seq.length
Enter fullscreen mode Exit fullscreen mode

List computations:

// https://docs.microsoft.com/en-us/dotnet/fsharp/tour
let daysList = 
    [ for month in 1 .. 12 do
          for day in 1 .. System.DateTime.DaysInMonth(2017, month) do 
              yield System.DateTime(2017, month, day) ]
Enter fullscreen mode Exit fullscreen mode

Active patterns:

// https://fsharpforfunandprofit.com/posts/convenience-active-patterns/
open System.Text.RegularExpressions
let (|FirstRegexGroup|_|) pattern input =
   let m = Regex.Match(input,pattern) 
   if (m.Success) then Some m.Groups.[1].Value else None  

// create a function to call the pattern
let testRegex str = 
    match str with
    | FirstRegexGroup "http://(.*?)/(.*)" host -> 
           printfn "The value is a url and the host is %s" host
    | FirstRegexGroup ".*?@(.*)" host -> 
           printfn "The value is an email and the host is %s" host
    | _ -> printfn "The value '%s' is something else" str

// test
testRegex "http://google.com/test"
testRegex "alice@hotmail.com"

Enter fullscreen mode Exit fullscreen mode

I've just found it nice and smooth to use. It's not hard to get from thought to code and have it work as intended. After a while learning all about building graphs in Rust, it's kinda nice to remember what that's like!

Some things I don't like:

  • Compiler errors, but I'm spoiled with Rust/Reason
  • Having to use the CLI to add things to solutions and references to packages and things. This is my own lack of familiarity with the ecosystem though.

That's really it, I like everything else a lot. It's the most fun I've had with an ML language so far, at least.

Try you some F#, today!

As an aside, does anyone have any experience using Clojure CLR? Seems not too popular, but a good idea in general.

This post isn't really about AoC, but here's an "obligatory" repo link if you'd like to play around with it.

Top comments (24)

Collapse
 
kspeakman profile image
Kasey Speakman • Edited

Great post. :)

I assume you are using VS Code with Ionide plugin? If you open a folder with an F# project (.fsproj) file, it will add an icon to the left that looks like this.

F sharp logo

When you click that, it shows the F# Project Explorer window. You can right-click on the project and Add File. That should create the file and also add it to the .fsproj automatically. The Project Explorer is still a little rough around the edges. But helpful for basic usage.

On Windows, I've been using Visual Studio 2017. It has a robust Solution Explorer that feels like normally managing files in an editor, but it automatically takes care of the .fsproj stuff. So no need to add them through CLI. However, VS does not have a built-in terminal window, so I use the MS-sponsored Whack Whack Terminal plugin for that. (to run npm/etc. commands from within VS for Fable projects.)

Collapse
 
deciduously profile image
Ben Lovy • Edited

Thanks so much for the advice!

I was using Ionide but had a rough go from the start and immediately fell back to the dotnet command. I'll give it another go, but I've also been meaning to start learning a bit about VS, too - might be a solid excuse. That plugin will definitely help it feel a little more comfortable. I've had an Elm project in the back of my head for a while - no reason it couldn't be Elmish!

Collapse
 
kspeakman profile image
Kasey Speakman • Edited

MVU style is amazing. Go for it either way! Elm is better for learning to write pure functions TBH. Fable-Elmish is structurally and syntactically very similar while being far less restrictive. For the latter, I do recommend keeping side effects out of init/update if you want to keep the refactor/test benefits from having pure functions. (Cuz F# does not stop you from putting side effects in those functions.)

Thread Thread
 
deciduously profile image
Ben Lovy

Interesting - I do love compiler-enforced discipline, but it's always nice to have an escape hatch - and F# seems like a more broadly applicable language if I'm going to invest some time in one or the other. I'll have to think about it.

Thread Thread
 
kspeakman profile image
Kasey Speakman • Edited

Yeah, I vote for F#. But wanted to give a props to Elm for teaching me the value of pure functions. I came from C# to F# and still fell back to a lot of mutation-based/imperative solutions for a while. Elm forced me do pure functions (along with MVU, which structures most of the code to be written in pure functions) and experience their benefits. But if you understand that pure (aka referentially transparent, aka deterministic) functions produce output based only on their inputs. And if you understand the value of using them. Then it is pretty easy to understand whether you have written a pure function or not in F#, even without a compiler warning. Plus F# is great for back-end work too. (Kestrel on .NET Core is known to be a pretty fast web server.)

Thread Thread
 
deciduously profile image
Ben Lovy • Edited

Awesome. I think Haskell drilled the concept in pretty well but I still always sort of miss the rigidity whenever it's gone. I'm heavily leaning F# now too - I'll have to look in to Kestrel!

Thread Thread
 
kspeakman profile image
Kasey Speakman • Edited

Kestrel is the built-in .NET Core web server. It isn't functional or anything, but it is very fast -- look for aspcore. Giraffe is a F#/functional lib on top of Kestrel. I also wrote my own for API routing only.

Thread Thread
 
deciduously profile image
Ben Lovy

Cool! Definitely looking forward to digging deeper in to this, thank you.

Collapse
 
deciduously profile image
Ben Lovy

Following up ...Visual Studio proper was so the way to go

Collapse
 
lyfolos profile image
Muhammed H. Alkan • Edited

If you want a better performance, easier JS interop (than Fable) you have to use OCaml. F# was "OCaml for .NET" before, and it's still interoptable with OCaml. They classified OCaml, for example ;; is optional ; is can be replaced with \n (Newline), foreach loop added for ... in ... so on. You can still use the OCaml syntax, using verbose syntax (It's still part of F# Grammar and Parser, it's not a new language). In my opinion, learning OCaml before learning F# will be more useful for you.

Collapse
 
deciduously profile image
Ben Lovy • Edited

I did learn OCaml before I learned F# - and strongly prefer the latter. Thanks for the tip, though!

I agree, JS interop via BuckleScript is really nice, but everything else was harder to use than the equivalent in F#

Collapse
 
lyfolos profile image
Muhammed H. Alkan

Ah, I just remembered it now. There is OCaml preprocessor or macro language named camlp. That makes you easier to code OCaml, makes you have more features like F# have. For example for each loop

let a_list = ["hello"; "world"] in
for s in a_list do
  print_endline s
done
Collapse
 
liltechnomancer profile image
Levi ᕙ(⇀‸↼‶)ᕗ

Nice post! Every language really should have Pipes. They are super! I have only used them in Elixir, but man I loved it.

Collapse
 
mark_nicol profile image
Mark Nicol

Lovely post and very inspiring. Arrrgh I don't need another language that I now want to try.

Collapse
 
deciduously profile image
Ben Lovy

Neither do I, Mark. Neither do I :(

Collapse
 
daxfohl profile image
Dax Fohl

A bit of experience using ClojureCLR several years ago. I had mostly .Net experience at the time and wanted to explore so tried it out. I created some WinForms and Console apps, successfully passing stuff to and from C# code. I can't say there were any glaring problems with it, but eventually it was obvious that .Net was a 2nd class platform. Just, tooling wasn't there, so I just moved to the Java ecosystem instead. F# is a lot tighter with .Net of course. (Though I'm surprised nobody ever did a JVM port!) I ended up settling on F# as my go-to: after just not being able to refactor in Clojure due to lack of type safety, I did some complete rewrites of fairly large Compojure apps to Suave, and never looked back.

Collapse
 
deciduously profile image
Ben Lovy

That makes a lot of sense - I have a feeling spending more time with F# is the answer for me as well

Collapse
 
jcmrva profile image
Josh M

Re: compiler errors - meaning the quality of the errors?

On another note, I see you're in Boston. Do you have any interest in helping to revive the Boston F# Meetup?

Collapse
 
deciduously profile image
Ben Lovy

Hey! Gosh, I'm so sorry I missed this.

Not necessarily the errors themselves, but the error messages. Those two compilers are extremely helpful, and will often nudge you in the right direction, which as a total beginner is extremely useful. The F# compiler is a little more matter of fact about what's wrong, like most compilers. I think as I get more comfortable I won't find it as opaque, and it's not a huge drag on the experience.

I absolutely am interested - send me a message!

Collapse
 
jeikabu profile image
jeikabu

Good stuff.
It was (I believe) the first .net language to get async support. We kind of take async/await for granted now but F# was a game changer for me.

Collapse
 
deciduously profile image
Ben Lovy

The units of measure stuff is also really awesome! I don't think I've seen anything else quite like it baked-in, only in libraries.

Collapse
 
sirluis profile image
Luis Henrique

I'm looking into Rust but f# looks awesome to learn.

Collapse
 
deciduously profile image
Ben Lovy

Those are my two favorites, I think! Very different, both worthwhile.

Collapse
 
alanmbarr profile image
Alan Barr

Really happy to hear how easy it was to jump in. I think with .net core F# should be much more approachable than in the past!