Intrinsic F# language features

Along with features inherited from F# predecessors, the F# language carries its own set of notable novel facilities. The outline of these facilities is discussed in the upcoming sections.

Indentation-aware syntax

Yes, this is correct; the F# compiler is sensitive to indentation in the source code (https://msdn.microsoft.com/en-us/library/dd233191.aspx), so correct code formatting is not just a matter of aesthetics. Why? Firstly, the improved code readability is enforced by the compiler, and secondly, this design choice dramatically decreases the amount of noise in the F# source code as block markers (such as curly brackets in C#) do not present, overall making the F# source code significantly shorter than the equivalent C# one.

Units of measure

This feature (https://msdn.microsoft.com/en-us/library/dd233243.aspx) allows you to decorate values with associated units and statically validate unit usage correctness by the compiler as well as infer units associated with the expression value based on units of operands. Let us look at the following example.

Here, I have defined two measures: <m> meters for distance and <s> seconds for time. Knowing how to find speed from acceleration and distance from physics, I defined a fallSpeed function to find the speed of objects falling from the given argument height at the time of hitting the ground as shown in the following code (Ch2_1.fsx):

[<Measure>] type <m> // meters 
[<Measure>] type <s> // seconds 
let fallSpeed (height: float<m>) = 
  2.0 * height * 9.81<m/s^2> |> sqrt 

Now using this function, it is easy to find that a water bottle that accidentally dropped from the top of the Empire State Building hit the pavement of 5th Avenue in New York City with a speed of 86.46 meters per second (<m/s>), hopefully not hurting a random bystander from the tourist crowd hanging out near the entrance.The following code represents the preceding example:

let empireStateBuilding = 381.0<m> 
fallSpeed empireStateBuilding 

Note that the compiler will not allow anything but float decorated with <m> as the argument for fallSpeed. Also, the function correctly infers that units of measure for the resulting speed are meters per second. Neat, right? But seriously, consider this CNN article back from 1999 titled Metric mishap caused loss of NASA orbiter (http://www.cnn.com/TECH/space/9909/30/mars.metric.02/). The $125 million loss of satellite would not occur if units of measure checks were in place. Unfortunately, NASA and Lockheed Martin software systems used for the satellite flight control were operating each in its own system of measures and integration tests failed to discover this defect prior to the actual flight beginning.

Overloaded operators

F# allows the overloading (https://msdn.microsoft.com/en-us/library/dd233204.aspx) of the existing operators as well as creating new unary and infix operators. It allows providing multiplicity of implementations for unary (prefix) and infix operations based on concrete types of operands. For example, an implementation of rational fractions arithmetic may use three versions of addition operation represented by infix operator + applicable to adding fraction to integer, integer to fraction, and fraction to fraction. Overloading has a positive side allowing to express semantic of manipulating objects of some domain tersely. But this feature is good in moderation as excessive overloading may be detrimental to code readability.

Inline Functions

Inline functions (https://msdn.microsoft.com/en-us/library/dd548047.aspx) represent a specific compilation technique. Normally a compiled function with non-generic type of arguments is associated with a single piece of MSIL and each function reference is compiled into invocation of this code and receiving back the evaluated result. However, it is impossible to have compiled MSIL for generic arguments within .NET type system. F# offers a smart workaround by statically evaluating arguments of each specific function invocation and creating MSIL adjusted for non-generic argument types of this particular function invocation. By following the outlined technique F# achieves function argument generalization under very limited support from .NET type system.

Type constraints and statically resolved type parameters

It is sufficient to have genuinely generic function type arguments in only very limited number of design and implementation situations . Usually, the addition of a custom combination of distinctive additional properties of the argument type is required in order to give the F# compiler a way of statically checking whether the type generalization is specific enough for the task. In most such cases, type inference is smart enough to derive such constraining from the static context, but sometimes, it may be desired that the developer provide some extra constraining. The process and further details of supplying the additional static constraints is described by the link: https://msdn.microsoft.com/en-us/library/dd233203.aspx. The book puts this matter under scrutiny in Chapter 10, Type Augmentation and Generic Computations.

Active Patterns

Active patterns (https://msdn.microsoft.com/en-us/library/dd233248.aspx) tremendously amplify the power of pattern matching by allowing the usage of custom functions within pattern matching rules. In other words, pattern matching can be specialized for any desired level of sophistication. Active patterns are absolutely essential for mastery over F#, and I will devote a lot of attention to them in the following chapters.

Computation Expressions

Computation expressions (https://msdn.microsoft.com/en-us/library/dd233182.aspx) represent quite an advanced topic. They provide tools for representation of complex nested computations sequenced and bound with simple looking syntax sugar. Some of F# language's very own features are implemented with the help of computation expressions, namely sequence expressions, query expressions, and asynchronous computations. F# also allows you to write custom computation expressions, providing tremendous extensibility power.

Query Expressions

Query expressions (https://msdn.microsoft.com/en-us/library/hh225374.aspx) represent the language-provided form of computation expressions addressing language integrated queries, also known as LINQ in F#. They are a part of mechanics addressing the information rich programming I've mentioned earlier, allowing data consumed from the multiplicity of sources and in the multiplicity of forms to be manipulated uniformly. For example, data obtained off OData service, web service defined with WSDL, or SQL server can be transformed to a certain extent without taking into consideration the specifics of their origin.

Asynchronous workflows

Asynchronous workflows (https://msdn.microsoft.com/en-us/library/dd233250.aspx) in F# are presented, in a manner similar to query expressions, by a language-provided form of computation expressions, and they demonstrate the mechanism's power and universal nature. They allow you to execute asynchronous code against implicitly provided thread pool at a high level of abstraction from asynchronous computations' arrangement details. As a corollary, writing F# asynchronous code is almost as simple as synchronous code.

Meta-programming

Meta-programming (https://msdn.microsoft.com/en-us/library/dd233212.aspx) is an extremely powerful and exciting technique that allows programs to write other programs. It may take different forms and occur at different levels: at native machine-level code, at MSIL level, or even at the source code level of F# or another programming language. A few years ago, I was quite excited about this feature and blogged a short series on this matter: F# Metaprogramming part 1: JIT Some Native Code on the Fly (https://infsharpmajor.wordpress.com/2012/03/04/how-hard-is-to-jit-some-native-code-from-f/), F# Metaprogramming part 2: Dynamic synthesis of executable F# code (https://infsharpmajor.wordpress.com/2012/04/01/how-to-dynamically-synthesize-executable-f-code-from-text/), and F# Metaprogramming part 3: Creating MSIL on the Fly (https://infsharpmajor.wordpress.com/2012/04/12/creating-msil-from-f-on-the-fly/).

However, usually, when developers consider F# meta-programming, a different program level is involved, namely F#, but in a partially compiled form associated with the language feature known as quoted expressions. When the F# compiler comes across specifically delimited F# code, then instead of making this code part of the program, it compiles it into a special object representing the F# expression. The great power of this feature is that when compiled in this manner, F# expressions can be further transformed into the form that's good for execution in a completely different environment, for example, inside a web browser in the form of JavaScript or in some Graphic Processing Unit (GPU), reaching, in principle, a vast amount of diverse computational platforms.

Type providers

Type providers (https://msdn.microsoft.com/en-us/library/hh156509.aspx) represent the meta-programming feature as well. However, instead of transforming some form of source code into executable form type providers does something completely different. A typical type provider represents a data source of certain kind as an assortment of types with their methods and properties ready to be seamlessly used exactly the same way as human-written types or libraries. It's worth noting that the provided types carry the same qualities as the hand-written ones. They can be statically checked, introspected by Intellisense, inferred by F# compiler.

For example, the SqlClient type provider (http://fsprojects.github.io/FSharp.Data.SqlClient/) allows F# developers to get type-safe access to the complete set of features of the Microsoft SQL server.

Another fantastically powerful use case for type providers is the interoperability between F# and other programming languages. One of the big successes in this field is F# R Type Provider (http://bluemountaincapital.github.io/FSharpRProvider/), allowing access from F# to a vast amount of R programming language libraries for statistical computing. Using F# in tandem with R Type Provider gave a big boost to using F# in the fields of machine learning and data science.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset