This post is part of our F# 8 series, in which we'll be digging into a few of the best features in the latest version of the language.
Lambda functions are a great tool that allow us to write functions on the fly wherever we need them. F#'s fun <arg> ->
syntax provides a brief, clear notation for these functions. But what if even a Lambda function is too much? Among other great features, F# 8 introduces the _.Member
shorthand, which lets you access members in just two characters!
Imagine you have a list of people that you want to transform to a list of birth years:
type Person =
{
BirthYear: int
Name: string
}
member this.Age year =
year - this.BirthYear
let people = [
{ BirthYear = 1964; Name = "Ben" }
{ BirthYear = 1992; Name = "Anne" }
{ BirthYear = 2013; Name = "John" }
{ BirthYear = 1993; Name = "Steve" }
{ BirthYear = 1964; Name = "Lynn" }
{ BirthYear = 1993; Name = "Jeff" }
{ BirthYear = 2012; Name = "Jule" }
]
Before F# 8 we'd use a Lambda function:
people
|> List.map (fun person -> person.BirthYear)
//int list = [1964; 1992; 2013; 1993; 1964; 1993; 2012]
While writing this quickly became an automatism for me, I do feel there are two downsides to this. Firstly, it does not read as simply as it could - before you see what you are accessing, have to go through boilerplate code that enables to access the property. Secondly, you are forced to name something in a miniscule scope. It might be a bit pedantic, but with naming being a major cause of headache amongst developers, I'd rather see that gone.
Shorthand lambda syntax to the rescue
Thanks to an issue that had been open since November 2016, we now have the _.Property
shorthand:
people
|> List.map _.BirthYear
//int list = [1964; 1992; 2013; 1993; 1964; 1993; 2012]
This does not just work for properties, but also for methods:
people
|> List.map _.Age(2024)
//int list = [60; 32; 11; 31; 60; 31; 12]
The shorthand works for everything that can be used in a Lambda function. For example, let's give it a go with an anonymous record:
let appleTree =
Some {| Apples = 50 |}
appleTree
|> Option.map _.Apples
// int option = Some 50
Limitations
There is one case where anonymous records don't work: you can not use it in the same scope as a discarded (_
) variable:
let getName myPersonOption _ =
myPersonOption
|> Option.map _.Name
This will result in a compiler warning: The meaning of _ is ambiguous here. It cannot be used for a discarded variable and a function shorthand in the same scope
In addition, shorthand lambda syntax is specific designed for member access - you cannot use it within the context of a more complex expression.
Conclusion
As you can see, the lambda shorthand is a great addition to the F# language that makes your code cleaner and more readable. Thanks to all the developers that contributed to F# 8!