3

Functional programming: Code with F# computation expressions

 1 month ago
source link: https://www.pluralsight.com/resources/blog/software-development/fsharp-computation-expressions
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Code with F# computation expressions

One of my favorite features of the F# language is computation expressions

Microsoft explains them as, “A convenient syntax for writing computations that can be sequenced and combined using control flow constructs and bindings. . . . Unlike other languages (such as do-notation in Haskell), they are not tied to a single abstraction, and do not rely on macros or other forms of metaprogramming to accomplish a convenient and context-sensitive syntax.”

In layman's terms, they're a really cool abstraction that allows a lot of super powerful transformations and operations in code flow. In this post, I explore functional programming in F# and share useful computation expressions you can use to streamline your code.

There are many reasons to use computation expressions, but one of the main benefits is readability. In functional programming, it’s very common to use Discriminated Unions and record types. With these kinds of types, you’ll often perform mapping operations to transform values from one type to another (e.g. SomeType<T> -> SomeType<U>). Computation expressions allow us to perform common operations like this in a way that can really improve the readability of those operations.

Under the hood, all that a computation expression does is call functions using a special syntax. In fact, most computation expressions will have a module exposing the implementation functions that can be called directly for when that may make more sense.

But the computation expression syntax allows us to write some code a little more declaratively, and sometimes that’s quite beneficial. For example, the following functions using the FsToolkit.ErrorHandling library are fully equivalent:

This class has only two members: Bind and Return. Bind is the function that will unwrap an option to it's inner value if it's Some, and if it's None it will just return None. Return essentially just wraps a value in Some.

The member names used for computation expressions have a well-defined pattern, but due to the nature of higher-kinded types, and the fact that any computation expression may not need all available functionality, they can't currently be modeled by a simple interface.

So a builder class doesn't need to implement an interface, it just has to define the relevant member methods. You can see which methods are available for this purpose with first-class support.

Out of the box, F# computation expressions can be used to support standard functional programming operations that you'd expect from monadic types. There are a lot more things you can do with the built-in computation expression functions, and you can also utilize custom operations to essentially create your own Domain-Specific Languages (DSLs)! 

Computation expressions are incredibly powerful, and I've used them when creating a simple SQL query builder, http request builder, and dependency injection container registrations. Try and see what you can build with them!

Josh DeGraw

Josh D.

Josh loves solving problems and building solutions. He dedicates himself to figuring out how to make things better and more efficient. He also enjoys working on front-end design systems/component libraries and developer tools. He has specialized in Typescript/React and C#/F# but is interested in other technologies as well. When he has time, he likes to contribute to open source projects (e.g. Fantomas) and enjoys collaborating on tools to improve the developer experience.

More about this author

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK