Page 25 - MSDN Magazine, September 2019
P. 25

for fun and for their work. F# powers financial institutions across the world, eCommerce systems, scientific computing, organiza- tions doing data science and machine learning, consultancies, and more. F# is also used quite a bit at Microsoft: As one of the primary languages used by Microsoft Research, it influenced and helped power the Q# development platform; parts of Azure and Office 365; and even the F# compiler and Visual Studio tools for F#! In short, it’s used everywhere.
Interested? Great! In this article, I’ll show you how to do some cool stuff with F# on .NET Core.
Overview
I’ll start with the basics of F# on .NET Core and walk though progres- sively more advanced (and more interesting) capabilities, including how you can use the .NET CLI to create a console application and library project on any OS. Although simple and bare-bones, this toolset alone can be enough to develop an entire application when coupled with an editor like Visual Studio Code and the official F# plug-in, Ionide (ionide.io). You can also use Vim or Emacs if that’s your thing.
Next, I’ll give a brief overview of some technologies for building Web services. Each has some different tradeoffs that are worth men- tioning. I’ll then show you an example using one of these technologies.
Finally, I’ll talk a bit about how you can leverage some of the high-performance constructs in .NET Core, like Span<'T>, to cut down on allocations and really speed up the hot paths in your system.
Get Started with F# Using the .NET CLI
One of the easiest ways to get started with F# is to use the .NET CLI. First, ensure you’ve installed the latest .NET SDK.
Now let’s create a few projects that are all connected to each other. Modern terminals support tab completion, so even though there’s
Figure 1 Typical F# Code
a bit to type, your environment should be able to complete much of it for you. To begin, I’ll create a new solution:
dotnet new sln -o FSNetCore && cd FSNetCore
This will create a new directory called FSNetCore, create a solu- tion file in that directory, and change directories to FSNetCore.
Next, I’ll create a library project and hook it up to the solution file:
dotnet new lib -lang F# -o src/Library dotnet sln add src/Library/Library.fsproj
I’ll add a package to that library:
dotnet add src/Library/Library.fsproj package Newtonsoft.Json
This will add the Json.NET package to the project.
The abundance of features and the vibrant community of enthusiastic developers have led many people to dive into F# both for fun and for their work.
I’ll now change the Library.fs file in the library project to be the following:
module Library
open Newtonsoft.Json
let getJsonNetJson value =
sprintf "I used to be %s but now I'm %s thanks to JSON.NET!" value
(JsonConvert.SerializeObject(value))
This is a module that contains a single F# function that uses JSON.NET to serialize a generic value into a JSON string with the rest of a message.
Next, I’ll create a console app that consumes the library:
dotnet new console -lang F# -o src/App
dotnet add src/App/App.fsproj reference src/Library/Library.fsproj dotnet sln add src/App/App.fsproj
I’ll replace the Program.fs contents in the console app project with the following:
open System
[<EntryPoint>] let main argv =
printfn "Nice command-line arguments! Here's what JSON.NET has to say about them:" argv
|> Array.map Library.getJsonNetJson
|> Array.iter (printfn "%s")
0 // Return an integer exit code
This will take each command-line argument, transform it into a string defined by the library function, and then iterate over those strings and print them out.
I can now run the project:
dotnet run -p src/App Hello World
This will print the following to the console:
Nice command-line arguments! Here's what JSON.NET has to say about them:
I used to be Hello but now I'm ""Hello"" thanks to JSON.NET! I used to be World but now I'm ""World"" thanks to JSON.NET!
Pretty easy, right? Let’s add a unit test and connect it to the solu- tion and library:
// Group data with Records type SuccessfulWithdrawal = {
Amount: decimal
Balance: decimal }
type FailedWithdrawal = { Amount: decimal Balance: decimal IsOverdraft: bool
}
// Use discriminated unions to represent data of 1 or more forms type WithdrawalResult =
| Success of SuccessfulWithdrawal
| InsufficientFunds of FailedWithdrawal | CardExpired of System.DateTime
| UndisclosedFailure
let handleWithdrawal amount =
// Define an inner function to hide it from callers // Returns a WithdrawalResult
let withdrawMoney amount =
callDatabaseWith amount // Let's assume this has been implemented :) let withdrawalResult = withdrawMoney amount
// The F# compiler enforces accounting for each case!
match w with
| Success s -> printfn "Successfully withdrew %f" s.Amount
| InsufficientFunds f -> printfn "Failed: balance is %f" f.Balance | CardExpired d -> printfn "Failed: card expired on %O" d
| UndisclosedFailure -> printfn "Failed: unknown :("
msdnmagazine.com
September 2019 17


































































































   23   24   25   26   27