Skip to content

WesleySkeen/Our-FSharp-Journey

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

25 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Our-FSharp-Journey

Recently we were tasked with migrating a c# project code to f#. The code in question is some ms Orleans grains. The idea of this repo is to document findings and useful things we learn along the way.

This doc will be a WIP and will expand as my journey goes on

Findings

Type Abbreviations

Type abbreviations are useful to provide documentation and avoid writing a signature repeatedly.

Symbols mean different things depending on the context

// The '*' here is a pairing in a tuple. Not to be confused with multiply
type TypeAbbreviationTuple = int * int

// example
let typeAbbreviationTuple = TypeAbbreviationTuple(1, 2)
let first = fst typeAbbreviationTuple // 1
let second = snd typeAbbreviationTuple // 2    

Some less obvious things with inputs / outputs

// This specifies that the first 2 integers are parameters and the last int is what is returned
type TypeAbbreviationFunction = int->int->int


// example
let typeAbbreviationFunction:TypeAbbreviationFunction = fun a b -> a + b
let result = typeAbbreviationFunction 10 20 // 30

Tuples

If you want to catch all exceptions from a parsing. Maybe this works in other contexts??

let tryParseStringToInt32 intStr =
   try
      let i = System.Int32.Parse intStr
      true,i
   with _ -> false,0 // this catches the exception and returns these values
       
let result = tryParseStringToInt32 "abc"
let first = fst result // this will be false
let second = snd result // this will be 0

Records

We can instantiate a Record without having to include its type

type Person = { First: string; Second: string }

let person = { First="Wes"; Second="Skeen" }
let typeName = person.GetType().Name // "Person"

With this approach we need to be aware that we can run into an issue if we have the same labels in multiple types. The compiler will use the last type defined

type Car1 = { NumberOfWheels: int;}
type Car2 = { NumberOfWheels: int;}

let car = { NumberOfWheels=4 }
let typeName = car.GetType().Name // "Car2"

If we want to get around this we could separate our objects using modules

module Module1 = type Shape = { NumberOfSides: int }
module Module2 = type Shape = { NumberOfSides: int }

let square = { Module1.NumberOfSides=4 }
let pentagon = { Module2.NumberOfSides=5 }
let typeName1 = square.GetType().Name // "Shape"
let typeName2 = pentagon.GetType().Name // "Shape"

keep in mind that a function return type can also be inferred

type TryParseResult = {Success:bool; Value:int}
let tryParseStringToInt32WithRecords intStr =
  try
    let i = System.Int32.Parse intStr
    {Success=true;Value=i}
  with _ -> {Success=false;Value=0}
  
let result = tryParseStringToInt32WithRecords "99"
let typeName = result.GetType().Name // "TryParseResult"

Run tests

> dotnet test src/Basics.Tests

References

Contributors

About

Playing with F# to get to grips with it

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published