Functional Programming in F# für .NET – Kursinhalte

Die Kurs Inhalte können variieren, je nach Wissensstand, Zeitrahmen und Trainingsschwerpunkten.
Es wird Wert gelegt auf die Grundlagen und dass man das Gelernte sofort anwenden kann.

Sofort Produktiv

  • einfache und mächtige F# Syntax, wenig Code, einfaches Refactoring
  • Code ausführen während man ihn schreibt
  • effiziente und gut verständliche Datenmodellierung (Domain Driven Design (DDD)) mit Algebraischen Daten Typen die automatisch Strukturellen Vergleich und Hashing bieten.
  • Masseinheiten werden vom Compiler bei Übergabe und Berechnungen auf Korrektheit geprüft (Meter, Kilogramm, Sekunde, Pixel, Dollar, SelbstDefiniert, etc.)
  • mit F# Type Providern Ihre Daten automatisch typisiert im Code mit IntelliSense anwenden. Type Provider sind ein einzigartiges Feature von F# (seit 2010, ich konnte es kaum glauben als ich es das erste mal 2010 gesehen habe, It’s magic!), das keine andere Programmiersprache bisher ermöglicht (mit Ausnahme von IDRIS seit März 2015).
  • Erstellen von eigenen Domain Specific Languages (DSL)
  • F# ist in Visual Studio (seit 2010) schon enthalten
  • Kompatibilität, .dll’s können von C#, VB.NET und umgekehrt verwendet werden.

Wichtige Grundlagen der Funktionalen Programmierung (FP)

  • Immutability: verstehen warum Immutability gut ist und hilft Probleme einfacher zu lösen und Code besser zu verstehen. Immutable Daten Strukturen
  • Type Inference : verstehen und Nutzen erkennen
  • Partial Application und Curring
  • Rekursion: rekursive Funktionen und rekursive Datentypen
  • Higher Order Functions : map, reduce, filter, etc.
  • Pattern Matching
  • Referential Transparency
  • Lazyness: Seq, lazy
  • Memoziation
  • Algebraischen Daten Typen (ADT) (sind keine POCOs (Plain-Old CLR Objects))

Wesentliche Unterschiede von F# zu C#

  • null als ungültiger Wert (nicht als gültiger default Wert von Referenz Typen in C#)
  • unit als leerer Wert (nicht void als kein Wert wie in C#, denn void und async vertragen sich nicht gut in C#)
  • async als Library (nicht als async und await Sprachkonstrukte wie in C#)
  • lock als Funktion (nicht als Statement wie in C#)
  • choice für Exception Handling (Exception free programming)

Automatisiertes Testen

  • interaktives Testen im REPL
  • automatisches Erzeugen von Testdaten und Ermittlung des kleinsten Datensatzes, der die Fehler-Analyse vereinfacht mit FsCheck
  • Testen von Webseiten mit Canopy (Automatisiertes Surfen)

Parallel Programming und Asynchronous Programming (Concurrent Programming)

  • Parallelen Code schreiben, dem man trauen kann (immer richtiges Ergebnis)
  • Async Code composition
  • Actors (F# MailboxProcessor)

Web Programmierung (wird im Grundkurs nur gestreift)

  • F# Code zu JavaScript compilieren (mit FunScript oder WebSharper)
  • Client- und Server-Code in F# schreiben (Code Reuse) und automatisch zu .NET für Server und JavaScript für Client compilieren (mit WebSharper)
  • IntelliSense in F# für JavaScript Library Funktionen dank automatischer TypeScript Definitions File Auswertung.


Zu F# Inhouse Schulungskurse

Documenting the available .NET standard formats of .ToString(fmt) with a small F# code snippet

Inspired by ploeh’s stringf

Listing all standard formats of .ToString for DateTime with

1: 
let dateFormats = docuPrint DateTime.Now

that results in the following, where you can pick your favorite format easily.

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
('M', "08 Mai")
('m', "08 Mai")
('d', "08.05.2015")
('g', "08.05.2015 19:03")
('G', "08.05.2015 19:03:24")
('t', "19:03")
('T', "19:03:24")
('u', "2015-05-08 19:03:24Z")
('s', "2015-05-08T19:03:24")
('O', "2015-05-08T19:03:24.8516093+02:00")
('o', "2015-05-08T19:03:24.8516093+02:00")
('D', "Freitag, 8. Mai 2015")
('U', "Freitag, 8. Mai 2015 17:03:24")
('f', "Freitag, 8. Mai 2015 19:03")
('F', "Freitag, 8. Mai 2015 19:03:24")
('R', "Fri, 08 May 2015 19:03:24 GMT")
('r', "Fri, 08 May 2015 19:03:24 GMT")
('Y', "Mai 2015")
('y', "Mai 2015")

The main logic is this simple, we try all single char formats on the given type.
Yes it’s a generic function, because of the inline.

1: 
2: 
3: 
let inline getAllFormatSpecifier someType =
    ['A' .. 'Z'] @ ['a' .. 'z']  
    |> List.choose (exToOption (tupleTee (string >> flip stringf someType))) 

It’s signature look like this

1: 
2: 
3: 
val inline getAllFormatSpecifier :
  someType: ^a -> (char * string) list
    when  ^a : (member ToString :  ^a * string -> string)

Here is how to read this nice function composition from left to right:

  1. List.choose keeps only Some‘s
  2. The Some comes from exToOption that converts exceptions to None and successful results to Some
  3. tupleTee keeps the input of the function togehter with the result of the function as a tuple
  4. string converts a character from the concatinated lists ['A' .. 'Z'] @ ['a' .. 'z'] to a string to fit the stringf
  5. and finally the parameter order needs to be exchanged with flip and go into stringf with the given someType

The full code

  1: 
  2: 
  3: 
  4: 
  5: 
  6: 
  7: 
  8: 
  9: 
 10: 
 11: 
 12: 
 13: 
 14: 
 15: 
 16: 
 17: 
 18: 
 19: 
 20: 
 21: 
 22: 
 23: 
 24: 
 25: 
 26: 
 27: 
 28: 
 29: 
 30: 
 31: 
 32: 
 33: 
 34: 
 35: 
 36: 
 37: 
 38: 
 39: 
 40: 
 41: 
 42: 
 43: 
 44: 
 45: 
 46: 
 47: 
 48: 
 49: 
 50: 
 51: 
 52: 
 53: 
 54: 
 55: 
 56: 
 57: 
 58: 
 59: 
 60: 
 61: 
 62: 
 63: 
 64: 
 65: 
 66: 
 67: 
 68: 
 69: 
 70: 
 71: 
 72: 
 73: 
 74: 
 75: 
 76: 
 77: 
 78: 
 79: 
 80: 
 81: 
 82: 
 83: 
 84: 
 85: 
 86: 
 87: 
 88: 
 89: 
 90: 
 91: 
 92: 
 93: 
 94: 
 95: 
 96: 
 97: 
 98: 
 99: 
100: 
101: 
102: 
103: 
104: 
105: 
106: 
107: 
108: 
109: 
110: 
111: 
112: 
113: 
114: 
115: 
116: 
117: 
118: 
119: 
120: 
121: 
122: 
123: 
124: 
125: 
126: 
127: 
128: 
129: 
130: 
131: 
132: 
133: 
open System

// http://blog.ploeh.dk/2015/05/08/stringf/
let inline stringf format (x : ^a) = 
    (^a : (member ToString : string -> string) (x, format))

let flip f a b = f b a
let tupleTee f x = x, f x
let exToOption f x = try Some(f x) with _ -> None

// function composition in F# is awesome !
let inline getAllFormatSpecifier someType =
    ['A' .. 'Z'] @ ['a' .. 'z']  
    > List.choose (exToOption (tupleTee (string >> flip stringf someType))) 

// print it nice to choose one
let inline docuPrint x =
    x
    |> getAllFormatSpecifier
    |> List.sortBy snd              
    |> List.iter (printfn "%A")

let dateFormats = docuPrint DateTime.Now
(*
('M', "08 Mai")
('m', "08 Mai")
('d', "08.05.2015")
('g', "08.05.2015 19:03")
('G', "08.05.2015 19:03:24")
('t', "19:03")
('T', "19:03:24")
('u', "2015-05-08 19:03:24Z")
('s', "2015-05-08T19:03:24")
('O', "2015-05-08T19:03:24.8516093+02:00")
('o', "2015-05-08T19:03:24.8516093+02:00")
('D', "Freitag, 8. Mai 2015")
('U', "Freitag, 8. Mai 2015 17:03:24")
('f', "Freitag, 8. Mai 2015 19:03")
('F', "Freitag, 8. Mai 2015 19:03:24")
('R', "Fri, 08 May 2015 19:03:24 GMT")
('r', "Fri, 08 May 2015 19:03:24 GMT")
('Y', "Mai 2015")
('y', "Mai 2015")
*)

let timespanFormats = docuPrint <| TimeSpan(1, 2, 3)
(*
('T', "01:02:03")
('c', "01:02:03")
('t', "01:02:03")
('G', "0:01:02:03.0000000")
('g', "1:02:03")
*)

// be caereful, it rounds
let floatFormats = docuPrint 0.425      
(*
('G', "0.425")
('R', "0.425")
('g', "0.425")
('r', "0.425")
('F', "0.43")
('N', "0.43")
('f', "0.43")
('n', "0.43")
('E', "4.250000E-001")
('e', "4.250000e-001")
('P', "42.50%")
('p', "42.50%")
('C', "Fr. 0.43")
('c', "Fr. 0.43")
*)

// be caereful, it rounds
let decimalFormats = docuPrint 0.425m
(*
('G', "0.425")
('g', "0.425")
('F', "0.43")
('N', "0.43")
('f', "0.43")
('n', "0.43")
('E', "4.250000E-001")
('e', "4.250000e-001")
('P', "42.50%")
('p', "42.50%")
('C', "Fr. 0.43")
('c', "Fr. 0.43")
*)


let intFormats = docuPrint 42   
(*
('X', "2A")
('x', "2a")
('P', "4'200.00%")
('p', "4'200.00%")
('E', "4.200000E+001")
('e', "4.200000e+001")
('D', "42")
('G', "42")
('d', "42")
('g', "42")
('F', "42.00")
('N', "42.00")
('f', "42.00")
('n', "42.00")
('C', "Fr. 42.00")
('c', "Fr. 42.00")
*)


let bigIntFormats = docuPrint 42I
(*
('X', "2A")
('x', "2a")
('P', "4'200.00%")
('p', "4'200.00%")
('E', "4.200000E+001")
('e', "4.200000e+001")
('D', "42")
('G', "42")
('R', "42")
('d', "42")
('g', "42")
('r', "42")
('F', "42.00")
('N', "42.00")
('f', "42.00")
('n', "42.00")
('C', "Fr. 42.00")
('c', "Fr. 42.00")
*)
val dateFormats : obj

Full name: DocumentingToString.dateFormats
val getAllFormatSpecifier : someType:'a -> 'b list

Full name: DocumentingToString.getAllFormatSpecifier
val someType : 'a
Multiple items
module List

from Microsoft.FSharp.Collections

——————–
type List<'T> =
  | ( [] )
  | ( :: ) of Head: 'T * Tail: 'T list
  interface IEnumerable
  interface IEnumerable<'T>
  member Head : 'T
  member IsEmpty : bool
  member Item : index:int -> 'T with get
  member Length : int
  member Tail : 'T list
  static member Cons : head:'T * tail:'T list -> 'T list
  static member Empty : 'T list

Full name: Microsoft.FSharp.Collections.List<_>
val choose : chooser:('T -> 'U option) -> list:'T list -> 'U list

Full name: Microsoft.FSharp.Collections.List.choose
Multiple items
val string : value:'T -> string

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

——————–
type string = System.String

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

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

——————–
type char = System.Char

Full name: Microsoft.FSharp.Core.char
type 'T list = List<'T>

Full name: Microsoft.FSharp.Collections.list<_>
namespace System
union case Option.Some: Value: 'T -> Option<'T>
union case Option.None: Option<'T>
val sortBy : projection:('T -> 'Key) -> list:'T list -> 'T list (requires comparison)

Full name: Microsoft.FSharp.Collections.List.sortBy
val snd : tuple:('T1 * 'T2) -> 'T2

Full name: Microsoft.FSharp.Core.Operators.snd
val iter : action:('T -> unit) -> list:'T list -> unit

Full name: Microsoft.FSharp.Collections.List.iter
val printfn : format:Printf.TextWriterFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printfn