type Person =
  {FirstName: string;
   LastName: string;
   Age: int;}

Full name: index.Person
Person.FirstName: string
Multiple items
val string : value:'T -> string

Full name: Microsoft.FSharp.Core.Operators.string

--------------------
type string = System.String

Full name: Microsoft.FSharp.Core.string
Person.LastName: string
Person.Age: int
Multiple items
val int : value:'T -> int (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.int

--------------------
type int = int32

Full name: Microsoft.FSharp.Core.int

--------------------
type int<'Measure> = int

Full name: Microsoft.FSharp.Core.int<_>
val p : Person

Full name: index.p
val point : float * float

Full name: index.point
val personWithAge : string * int

Full name: index.personWithAge
val x : float

Full name: index.x
val y : float

Full name: index.y
type MyTuple = string * int * Person

Full name: index.MyTuple
type LoggingLevel =
  | Debug
  | Info
  | Error

Full name: index.LoggingLevel
union case LoggingLevel.Debug: LoggingLevel
union case LoggingLevel.Info: LoggingLevel
union case LoggingLevel.Error: LoggingLevel
val level : LoggingLevel

Full name: index.level
type Shape =
  | Circle of radius: float
  | Rectangle of width: float * height: float

Full name: index.Shape
union case Shape.Circle: radius: float -> Shape
Multiple items
val float : value:'T -> float (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.float

--------------------
type float = System.Double

Full name: Microsoft.FSharp.Core.float

--------------------
type float<'Measure> = float

Full name: Microsoft.FSharp.Core.float<_>
union case Shape.Rectangle: width: float * height: float -> Shape
val circ : Shape

Full name: index.circ
val rect : Shape

Full name: index.rect
val calculateArea : shape:Shape -> float

Full name: index.calculateArea
val shape : Shape
val w : float
val h : float
val r : float
val circleArea : float

Full name: index.circleArea
type OperationResult =
  | Success of data: obj
  | NotFound
  | Error of errorMessage: string

Full name: index.OperationResult
union case OperationResult.Success: data: obj -> OperationResult
namespace Microsoft.FSharp.Data
union case OperationResult.NotFound: OperationResult
union case OperationResult.Error: errorMessage: string -> OperationResult
type HttpRequest =
  | Get of url: string
  | Post of url: string * body: byte array

Full name: index.HttpRequest
union case HttpRequest.Get: url: string -> HttpRequest
union case HttpRequest.Post: url: string * body: byte array -> HttpRequest
Multiple items
val byte : value:'T -> byte (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.byte

--------------------
type byte = System.Byte

Full name: Microsoft.FSharp.Core.byte
type 'T array = 'T []

Full name: Microsoft.FSharp.Core.array<_>
type Credentials =
  | UserPass of user: string * password: string
  | Certificate of certFilePath: string
  | None

Full name: index.Credentials
union case Credentials.UserPass: user: string * password: string -> Credentials
union case Credentials.Certificate: certFilePath: string -> Credentials
union case Credentials.None: Credentials

Introduction to
functional data types in F#



Mark Vincze - @mrkvincze

The plan

  1. Sample problem
  2. Implement in C#
  3. Basics of F# data types
  4. Implement in F#

The exercise

  • Implement a data model for the standard 52-card deck (French playing cards)
    • 4 suits: ♦ ♥ ♣ ♠
    • 9 value cards from 2 to 10
    • 4 face cards: Jack, Queen, King, Ace
    • Special card without a suit: Joker
Image: Vintage French playing card by William Creswell, License: CC 2.0

Additional requirements

  1. Implement a standalone data model, not tied to any algorithm

  2. Adhere to Domain Driven Design
    Main principles

    • Use terminology natural to domain experts
    • Make illegal states not representable

"Business" logic example:
Rummy scoring

  • Calculate the score of a card in Rummy
    • Queen of spades: 40
    • Aces: 15
    • Other face cards: 10
    • 10s: 10
    • Everything else: 5

Data models in OO languages

  • Immutability is not the default
  • "Either" is not easy to express
  • Inheritance and pure data do not play well

Data types in FP languages

  • Immutability by default
  • Composability
  • Value semantics
  • Originates from set theory and category theory

Record

  • Immutable reference type objects
1: 
2: 
3: 
4: 
5: 
type Person = {
    FirstName : string
    LastName : string
    Age : int
}

Record

  • Immutable by default
1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
9: 
type Person = {
    FirstName : string
    LastName : string
    Age : int
}

let p = { FirstName = "Jane"; LastName = "Smith"; Age = 25 }

p.Age <- 30 // This doesn't compile

Record

  • Opt-in for mutability
1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
9: 
type Person = {
    FirstName : string
    LastName : string
    mutable Age : int
}

let p = { FirstName = "Jane"; LastName = "Smith"; Age = 25 }

p.Age <- 30 // Now this works

Tuple

  • Multiple values put together
1: 
2: 
3: 
4: 
5: 
6: 
let point = (1.5, 4.3)  
let personWithAge = ("Jane Smith", 25) 

let x, y = point

type MyTuple = string * int * Person

Tuple

Also called: Product type

A

a1
a2
a3

*

B

b1
b2

=

A*B

a1, b1
a2, b1
a3, b1
a1, b2
a2, b2
a3, b2

Discriminated union

  • Represents a choice of multiple options
    Example without data
1: 
2: 
3: 
4: 
5: 
6: 
type LoggingLevel =  
| Debug
| Info
| Error

let level = Info

Discriminated union

  • Every case can have a value
    Example
1: 
2: 
3: 
4: 
5: 
6: 
type Shape =  
| Circle of radius : float
| Rectangle of width : float * height : float

let circ = Circle (2.0) 
let rect = Rectangle (width = 10.0, height = 2.3)

Discriminated union

  • Usage, pattern matching
1: 
2: 
3: 
4: 
5: 
6: 
let calculateArea shape =  
    match shape with
    | Rectangle (w, h) -> w * h
    | Circle r -> r * r * 3.14

let circleArea = calculateArea (Circle 5)

Discriminated union

Also called: Sum type

A

a1
a2
a3

+

B

b1
b2

=

A+B

A a1
A a2
A a3
B b1
B b2

Discriminated unions in practice

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
type OperationResult =  
| Success of data : Data
| NotFound
| Error of errorMessage : string

type HttpRequest =  
| Get of url : string
| Post of url : string * body : byte array

type Credentials =  
| UserPass of user : string * password : string
| Certificate of certFilePath : string
| None

Thank you!