Die Vorteile funktionaler Programmierung (im speziellen F#)

TL;DR: Weniger Code mit FP und F#.

Was ist es denn genau, was in der Funktionalen Programmierung mit F# den Code, also die Problemlösung, so vereinfacht und verkürzt?

Zu meinem Blog-Post "Less Code and Less Bugs : with Functional Programming languages"
http://functionalsoftware.net/less-code-and-less-bugs-with-functional-programming-languages-589/
bei dem es darum geht, das "weniger Code auch weniger Fehler" hat,
möchte ich hier aufzeigen mit welchen speziellen Sprachkonstrukten F#
  • das Code Verständnis erhöht und

  • dabei prägnanten Code ermöglicht

    (prägnant = knapp, treffend, gehaltvoll.)

    (concise = giving a lot of information clearly and in a few words; brief but comprehensive.)


Es folgt eine Auflistung von ausgewählten F# Features, die in etwa in dieser Reihenfolge aufeinander aufbauen für eine Problemlösungs-Formulierung, und massgeblich für das Code Verständnis und Code Korrektheit dienlich sind.

Was das Code Verständnis und Code Korrektheit am meisten fördert, sind:
  • Funktionen

    Input -> Output : den Output an einem klar definierten Ort im Code und die exakte Type Information des Output.

  • Die Pipe |>

    und Arrow >> Syntax ermöglicht den Daten/Program-Fluss in eine Richtung (ähnlich einem visuellen Flow-Diagram), die der natürlichen Leserichtung von links nach rechts (in unserer Kultur) folgt. Dies erleichtert auch das Naming, weil nicht für jedes Zwischenergebnis das nur einmal weiter gegeben wird ein Name/Bezeichner gefunden werden muss. Je nach verwendeter Namenskonventionen kann dies sehr mühsam zu lesen sein (Wortlängeneffekt, Erinnerungsleistung, Speed-Reading). Statt benannte Zwischenergebnisse Schritt für Schritt anzuwenden x = f() ; y = g(x) ; z = y das definieren was es ist z = f() |> g

  • Higher Order Functions (HOF) https://en.wikipedia.org/wiki/Higher-order_function

    sind Funktionen die Funktionen transformieren und mit minimalem syntaktischen Aufwand codiert werden. Man braucht nur den Funktionsnamen zu übergeben und die Interface-Typen werden von der Type-Inference automatisch ermittelt. Man braucht so nichts zu deklarieren (keine Func, Action, delegate, Interface), einfach nur zusammenbauen.

  • Expressions

    statt Statements (Referential Transparency, Pure Functions) - kurz : das WAS statt das WIE

  • Immutability

    als default und Mutation als Ausnahme.

  • Type Inference https://de.wikipedia.org/wiki/Typinferenz

    nicht weil man weniger Typen Signaturen schreiben muss, sondern weil es "fast" nebensächlich ist und es einfach passen muss, was die Type Inference im Editor während des Code schreibens prüft und signalisiert.

  • Algebraic Data Types (ADT) https://en.wikipedia.org/wiki/Algebraic_data_type

    Prägnanter exakter Daten Design mit Summen- und Produkt-Typen, die auch rekursiv zusammen gestellt (Composition) werden können.

  • Pattern Matching https://msdn.microsoft.com/en-us/library/dd547125.aspx

    ein vom Compiler überwachter Verzweigungs-Control-Flow damit kein (Spezial)-Fall vergessen wird. Man stelle sich das als super intelligentes switch-case Konstrukt vor, das mit den Algebraic Data Types perfekt harmoniert.

  • Computation Expression (CE) https://msdn.microsoft.com/en-us/library/dd233182.aspx

    ermöglicht Code-Plumbing hinter den Kulissen zu erledigen. So ist nur die Essenz in der Computation Expression ersichtlich. Die Logik dahinter, der Computation Builder, kann wiederverwendet werden. Mittels dieser Computation Expression lassen sich elegant z.B. Monaden usw. implementieren.

  • Units of Measure https://msdn.microsoft.com/en-us/library/dd233243.aspx

    vom Compiler geprüfte und berechnete Masseinheiten.

  • Domain Specific Language (DSL), Domänenspezifische Sprache https://de.wikipedia.org/wiki/Dom%C3%A4nenspezifische_Sprache

    F# eignet sich hervorragend um embedded-DSL's zu implementieren, denn man braucht dazu keine Lexer/Parser zu schreiben und kann die DSL in der Entwicklungsumgebung anwenden. Dies ist einfach möglich, da F# nebst kompliliertem Code auch als Scripting verwendet werden kann, das dann wiederum Kompiliert werden kann. Somit hat man für die eigene Domain Specific Language die Spracheigenschaften von F#, wie strict-static-typing und die Entwicklungsumgebung mit samt dem Debugger (wenn nötig). Ein bekanntes und viel angewandtes Beispiel einer embedded-DSL ist FAKE, ein F# Open Source Build Automatisierungs Scripting Tool ("make").


Hier einige Referenzen mit Beispielen die zeigen wie prägnant F# Code sein kann, im Vergleich mit C# Code.

"An F# rewrite of a fully refactored C# Clean Code example"
http://functionalsoftware.net/fsharp-rewrite-of-a-fully-refactored-csharp-clean-code-example-612/

"Analyzing Government Data"
in C# #csharp http://blogs.msdn.com/b/dave_crooks_dev_blog/archive/2015/04/20/intro-to-c-and-analyzing-government-data.aspx
und F# #fsharp http://fssnip.net/qE

"Does the Language You Use Make a Difference (revisited)?"
http://simontylercousins.net/does-the-language-you-use-make-a-difference-revisited/

"F# means less code"
http://fpbridge.co.uk/why-fsharp.html#conciseness

Less Code and Less Bugs : with Functional Programming languages

With a FP language many problems can
be solved with elegantly less code and
less-code leads to less-bugs.

Functional Programming (FP) insider know that, because they have personally experienced it. This can be tweeted and blogged many times, but how can others believe this? How do you prove it?

That problem inspired me to do some investigation. We need facts. What I’ve found so far are two studies that show this from a data analysis side. There is some evidence that both is true, according to these newer papers from 2014, based on data analysis of source code and its history from Github and from Rosetta Code :

Functional languages have a smaller relationship to defects than other language classes where as procedural languages”
– [1] A Large Scale Study of Programming Languages and Code Quality in Github
Functional and scripting languages provide significantly more concise code than procedural and object-oriented languages.”
– [2] A Comparative Study of Programming Languages in Rosetta Code


In [2] the data analysis covers 8 widely used languages representing the major programming paradigms
- procedural: C and Go;
- object-oriented: C# and Java;
- functionalF#  and  Haskell;  
- scripting:  Python  and  Ruby


I think the “less code” property is underestimated, because the too easy Lines of Code (LOC) counting is ridiculed. Looking beyond the LOC of the code base to the more important depending consequences :

less code  ->  less to read (more often than write!) and understand   -> 
less to review ->  less to communicate ->  less to refactor -> 
less to test  ->  less bugs  -> 
less to maintain  ->  less cost!!!

Btw. less code -> more time to think -> better solution -> more fun!


References

Other related analysis about software quality metrics, especially circular dependencies can be found here:
- “Comparing F# and C# with dependency networks
- “Cycles and modularity in the wild – Comparing some real-world metrics of C# and F# projects”

[1] A Large Scale Study of Programming Languages and Code Quality in Github
Baishakhi Ray, Daryl Posnett, Vladimir Filkov, Premkumar T Devanbu, Department of Computer Science, University of California, Davis, CA, 95616, USA
2014 http://dl.acm.org/citation.cfm?id=2635922


[2] A Comparative Study of Programming Languages in Rosetta Code
Sebastian Nanz, Carlo A. Furia, Department of Computer Science, ETH Zurich, Switzerland
2014 http://arxiv.org/abs/1409.0252



Yet Another Fizz Buzz (YAFB) in F#

Fizz Buzz kennt sicher jeder der auch Hello World kennt.
Meinst wird Fizz Buzz mit der Modulo Funktion gelöst.

Hier wird eine Lösung in F# gezeigt, die endlose Sequenzen verwendet und das Problem sehr beschreibend (deklarativ) löst, ohne dass man die mathematische Bedeutung der Modulo Funktion kennen muss.

Es werden zwei einfache Hilfsfunktionen verwendet die man eigentlich wiederverwendbar in einer Funktions-Bibliothek hinterlegen kann.
Mit der Funktion cycle werden unendlich lange Sequenzen der übergebenen Muster erzeugt.

   let cycle x = Seq.initInfinite (fun _ -> x) |> Seq.concat

Und zipWith verknüpft die Elemente zweier endlosen Sequenzen mittels der übergebenen Funktion f.

   let zipWith f xs ys = Seq.zip xs ys |> Seq.map (fun (x,y) -> f x y)

Nun zum eigentlichen Fizz Buzz, das sehr beschreibend gelöst ist, wie wenn man das Problem jemandem zum ersten mal erklärt.

Die Nummerierung von 1 bis 100 als String.

   let numbers  = seq [1 .. 100] |> Seq.map string

Zwei-mal nichts (“”) dann “fizz” und wiederholend (cycle).
Vier-mal nichts (“”) dann “buzz “und wiederholend (cycle).

   let fizz = seq [“”;””;”fizz”]       |> cycle
   let buzz = seq [“”;””;””;””;”buzz”] |> cycle

Dann die Logik wie alles zusammen agiert:

   let fizzBuzz = zipWith (+) fizz buzz |> zipWith max numbers

Mit zipWith (+) werden die zwei endlosen Sequenzen fizz und buzz elementweise zusammengefügt.
Aus zwei Leer-Strings ergibt sich so wieder ein Leer-String und “fizzbuzz” kommt so zustande “fizz” + “buzz”.

Etwas trickreich oder ungewohnt ist das zipWith max numbers, die Maximum Funktion max ist generisch und in diesem Anwendungsfall wird das Maximum von strings bestimmt. Man kennt das vom Sortieren von strings, diese werden anhand des ASCII codes sortiert.
So gibt auch max den String aus der weiter hinten im Alphabet respektive der ASCII Tabelle befindet.
Und da der Leer-String “” kleiner ist als “1”, “2” und “1” und “2” kleiner sind als “fizz” und “buzz” werden alle “” mit Inhalt also den numbers bestückt und “fizz” und “buzz” sind den Zahlen überlegen.

Und zu guter Letzt erfolgt die Ausgabe des Ergebnis der ersten 20 Elemente

   fizzBuzz |> Seq.take 20 |> Seq.toList

was folgendes anzeigt:

val it : string list =
  [“1″; “2”; “fizz”; “4”; “buzz”; “fizz”; “7”; “8”; “fizz”; “buzz”; “11”;
   “fizz”; “13”; “14”; “fizzbuzz”; “16”; “17”; “fizz”; “19”; “buzz”]


Und der vollständige F# Code:

 
let cycle x         = Seq.initInfinite (fun _ -> x) |> Seq.concat
let zipWith f xs ys = Seq.zip xs ys |> Seq.map (fun (x,y) -> f x y)
let numbers         = seq [1 .. 100]           |> Seq.map string
let fizz            = seq [“”;””;”fizz”]       |> cycle
let buzz            = seq [“”;””;””;””;”buzz”] |> cycle
let fizzBuzz        = zipWith (+) fizz buzz |> zipWith max numbers

fizzBuzz |> Seq.take 20 |> Seq.toList


Ausführbar auf http://tryfs.net/snippets/snippet-tl
Aufgenommen in http://fssnip.net/tl 

Keywords: FizzBuzz without modulo, FizzBuzz ohne Modulo

Zuverlässige Software durch weniger bewegliche Teile

Jedes mechanische System wird einfacher und wartungsfreundlicher, je weniger bewegliche Teile es hat. Die Einfachheit macht es auch langlebiger und weniger Störungsanfällig.

In der Softwareentwicklung findet man auch “bewegliche Teile”, so werden Variablen definiert in C#, C++

1: 
int myVariable = 0; 

in F# mit mutable

1: 
let mutable myVariable = 0

Jetzt könnte man denken, das ist ja furchtbar, immer noch dieses mutable hinzuschreiben. Und genauso ist es, denn der Standart (default) ist ohne mutable

1: 
let myValue = 0

Das hat seine Bedeutung, es ist sicher aufgefallen dass im Beispiel die Benennung von Variable auf Value gewechselt hat. Der Grund ist, in F# gibt es Standart mässig nur Values. Will man Veränderliche, so ist man gezwungen mutable hinzuschreiben. Also die beweglichen Teile zu markieren, so wird mutable auch als Code-Smell, als nicht so fein duftender Code bezeichnet.

Unveränderlich (Immutable)

Was hat es nun mit den Values auf sich?

Values sind einmal zugewiesen nicht wieder veränderbar. In C++ und C# ist es genau umgekehrt, man kann variablen mit const markieren. Das wird kaum angewandt, weil zu aufwendig oder nur dann wenn z.B. Mathematische oder Physikalische Konstanten definiert werden.

Ein F# Value ist konstant.

Ja aber bitte, wie soll man nur mit Konstanten programmieren können? Die Frage ist gut, die Antwort wird sie überraschen.

Angenommen sie wollen in eine string (.Net) myString = “aBc” das B durch ein kleines b ersetzen, wie machen sie das?

Nein, nicht so

1: 
myString[1] = 'b'

Sie könnten

1: 
myString.ToLower()

verwenden, was erhält man?

Ist nun myString = "abc" ?

Nein, man erhält einen neuen string “abc” als Rückgabewert von der Funktion ToLower().

Ah ja klar.

Es fällt auf, dass die string Instanz eigentlich eher ein Value ist, als eine Variable, also der string immutable ist, das Gegenteil von mutable.

Values sind immer zugewiesen, es gibt keine nicht initialisierten Values in F#.

Initialisierte Values (keine null Referenzen)

Es mag in C#/C++ nicht initialisierte Variablen oder Objekte geben.

1: 
2: 
object myObject;        // war früher in C/C++ nicht unbedingt null
object myObject = null; 

Bedeutet null nun, nicht initialisiert oder nicht zugewiesen oder nicht vorhanden oder kein Ergebnis oder Fehler ?

1: 
return null;

Da müssten jetzt die Alarmglocken losgehen, oder wie ist das denn genau in den von Ihnen angewandten Codierrichtlinien definiert?

Wie oft kommt dies im Code vor?

null

1: 
2: 
3: 
if x == null    // C++/C#
if x != null    // C++/C#
if x <> null    // VB

Nothing

1: 
2: 
If x Is Nothing Then // VB.NET
If IsNothing(x) Then // VB.NET

Nullable

Die Möglichkeit einen nicht-Referenz Type wie z.B. int auch null setzen zu können.

1: 
2: 
3: 
4: 
System.Nullable<int> x = 4;
int? x = 4;

int? a = null;

Der F# Option type ersetzt die null und das Nullable auf einsichtigere Weise mit static typing.

Die Bedeutungen von null und deren negative Konsequenzen

Meint null nun, nicht initialisiert oder nicht gültig?

Die Frage an C# Entwickler, Antwort oft: Beides!

In F# ist alles IMMER initialisiert, eine Option.None (ähnlich null) sagt, dass es keinen (gültigen) Wert hat.

Der Option Type als Rückgabe Parameter einer Funktion besagt, dass die Funktion auch None liefern kann. Somit bei static typing immer geprüft wird UND in Interfaces ist klar was optional ist!

Ob eine C# Methode null liefert oder nicht weiss man nicht explizit.

Also sollte man bei Verdacht immer prüfen? Um sogenanntes FailSafe Verhalten zu erzeugen?

Schön dass String in .Net ein immutable Type ist, aber leider leider kann er auch null sein. Dazu gibt es dann so nette Funktions Klassiker wie String.IsNullOrEmpty()

1: 
result = s == null || s == String.Empty; // String.IsNullOrEmpty()

All dies ist in F# nur dann ein Problem, bei Interop mit C# oder VB. Sonst ist die Welt in Ordnung.

Wie oft geht dies vergessen und führt so zu Fehlverhalten in der Software (Null-Refernece Exception)?

Was dazu führen kann (Fail-Save Programming), dass auch zuviele und unnötige null Tests gemacht werden und der Code fast ausschliesslich daraus besteht und ein Reviewer die Logik des Codes über weite Flächen erkunden muss.

In F# kann man darauf verzichten. Der Code ist Spezifikation und enthält nur das Wesentliche.

Das Problem ist ja, dass man nicht wissen kann, ob an dieser und jener Stelle eine null Prüfung gemacht werden muss oder nicht. Da kann man Code Annotations machen und externe Tools bemühen, die Code Dokumentation aufblähen, nur weil es keine Konvention oder Interface hat.

Der Option Type in F# stellt so ein Interface zu Verfügung. Das Interface kann der Compiler überprüfen. Man erkennt ob eine Funktion eine Option als Parameter verwendet und ob eine Option zurückgegeben wird. Es ist alles klar definiert. Keine Annahmen, die je nach Projekt oder Software Team in einer Konvention definiert wurde, z.B. in den Codierrichtlinien.

Dies ist nichts weiter als die Behandlung von Symtomen, anstatt die Ursache, die Null-Referenz zu bekämpfen. In F# ist keine null nötig und der F# Compiler kennt die “Codierrichtlinien” und prüft ob die Option korrekt ausgewertet wird.

So jetzt vergessen wir all diese Bauchschmerzen.

In F# gibt es nur initialisierte Values.

Somit braucht man die null nicht.

Und dies erübrigt auch die null Abfragen*.

So einfach und so praktisch!

*) Dies wohlbemerkt innerhalb der F# Welt. Bei Anwendung und Interfacing von nicht F# Modulen, muss man leider aus Sicherheitsgründen alles was rein kommt überprüfen.

Also dies ist nur ein Teil der wegfallenden beweglichen-Null-Teile, die nicht nur das Denken des Entwicklers vereinfacht auch der Code und somit die Software selbst.

Man kann es als Evolution der Programmiersprachen sehen

1: 
2: 
3: 
4: 
5: 
6: 
1965    Algol   null Referenz                                           Tony Hoare gilt als Erfinder der null Referenz
1972    C       Pointer (null)                                          Speicher Verwaltung mit malloc
1985    C++     nicht Initialisierte Objekte (null), Pointer (null)     Speicher Verwaltung mit malloc
2001    C#      nicht Initialisierte Objekte (null)                     Garbage-Collector verwaltet den Speicher
2002  VB.Net    nicht Initialisierte Objekte (null)                     Garbage-Collector verwaltet den Speicher
2002    F#      initialisierte Values, Static Typing                    Garbage-Collector verwaltet den Speicher

Ja F# gibt es seit 2002. Warum F# gut ein Jahrzehnt später populär wird liegt wohl daran, dass Microsoft F# erstmals in Visual Studio 2010 mit auslieferte, zuvor musste man es separat installieren, um es im Visual-Studio zu nutzen.

Static Typing

1: 
2: 
3: 
4: 
5: 
Dim Text As String  = "Hello world"     // VB
CString Text        = "Hello world";    // C++
String Text         = "Hello world";    // C#
var Text            = "Hello world";    // C#3 - Inferred type: String
let Text            = "Hello world"     // F#  - Inferred type: String  

Dass Text ein String sein muss, erkennt das F# Type-System automatisch ohne zu kompilieren! Der Tooltip unterm Mauszeiger zeigt den type. Dies verkürzt den Code, vorallem bei Funktions Deklerationen. Da werden von allen Parametern die Typen automatisch erkannt. Es ist also viel mächtiger als das C# var Konstrukt.

Dies vereinfacht das Code Refactoring, man muss die Type Spezifikation nicht “rumschleppen” und benötigt folge dessen kein extra Tool dazu (das auch noch auf die Compiler Version abgestimmt sein muss), weil es der Compiler selbst ist. Und es ist, dem Anschein zu Trotz, weil da ja keine Typen mehr stehen, strikt Type-Safe.

Die Vorteile von immutable sind

  • thread safety guarantee
  • besser testbar
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 mutable myVariable : int

Full name: ZuverlässigeSoftwaredurchwenigerbeweglicheTeile.myVariable
val myValue : int

Full name: ZuverlässigeSoftwaredurchwenigerbeweglicheTeile.myValue
namespace System
Multiple items
type Nullable =
  static member Compare<'T> : n1:Nullable<'T> * n2:Nullable<'T> -> int
  static member Equals<'T> : n1:Nullable<'T> * n2:Nullable<'T> -> bool
  static member GetUnderlyingType : nullableType:Type -> Type

Full name: System.Nullable

——————–
type Nullable<'T (requires default constructor and value type and 'T :> ValueType)> =
  struct
    new : value:'T -> Nullable<'T>
    member Equals : other:obj -> bool
    member GetHashCode : unit -> int
    member GetValueOrDefault : unit -> 'T + 1 overload
    member HasValue : bool
    member ToString : unit -> string
    member Value : 'T
  end

Full name: System.Nullable<_>

——————–
System.Nullable()
System.Nullable(value: 'T) : unit
module String

from Microsoft.FSharp.Core
val Text : string

Full name: ZuverlässigeSoftwaredurchwenigerbeweglicheTeile.Text

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

Warum Unternehmen noch zögern mit F#

Ich denke die wesentlichen 3 Gründe (“als grob zitierte Aussagen”) warum sich ein Unternehmen noch nicht getraut F# einzusetzen, nebst all den bekannten Vorteilen, sind:
  • 1. “Eine andere Sprache bringt nichts” “Das Problem das wir haben ist nicht das Programmieren, wozu dann eine andere Programmiersprache?” Das “Funktionale” an einer Funktionalen Programmiersprache ist weit mehr als Lambda-Funktionen und LINQ-Expressions. Es ist nicht nur die Sprache die bei F# anders ist, es ist die Funktionale DENKWEISE! Lernen anders zu Denken, um Probleme einfacher zu lösen, hat noch niemandem geschadet, im Gegenteil! Die Funktionale Denkweise birgt jede Menge neuer Konzepte, Techniken und Tricks, die Objekt-Orientierten-Praktikern meist unbekannt sind. Und die Denkweise wirkt sich auf die Software Entwicklung aus und das auch in anderen Programmiersprachen.
“Without exception, everybody I know who learned F# would say that it made them a better C# programmer. That’s the kind of thing that actually will make a difference during the week.” — Eric Sink (@eric_sink)  [1]   “becoming a better programmer” Warum das so ist? Es ist die Denkweise die sich erweitert hat und die Möglichkeiten diese Umzusetzen.
  • 2. “Es gibt zur Zeit zu wenig F# Entwickler” “Diese einfach vom Markt einzukaufen ist ja z.Z. nicht so einfach möglich.” Dann bildet doch einige aus, am besten ein Team! Ihr werdet sicher Freiwillige finden. Es sind diejenigen Entwickler die schon ein Auge auf Funktionale Programmierung (FP) oder F# geworfen haben und sich privat damit auseinandersetzen. Es sind meist die Talentiertesten der Entwickler die das tun und diese sehen sich auch um am Markt. Lasst sie nicht zu einer anderen Firma abwandern, weil man dort FP oder F# einsetzt und bei euch nicht!
“Startups are beginning to realize the potential for leveraging F# as a way to attract talented developers away from their otherwise satisfactory jobs to try something different just so they can finally turn their F# hobby into a full-time job.” [1]   “F# made me a far better C# developer. I’m delighted I can write F# a lot in my day job now, and I left an otherwise great position to do so.” — Ryan Riley (@panesofglass) [1]
  • 3. “Schulungskosten” “C# 6 hat auch ganz viel Neues, da haben wir erst mal zu tun.” Was auch Schulungsaufwand bedeutet! Und diejenigen die Neues Lernen möchten, sollte man im Unternehmen halten. Ja man muss investieren in die eigenen Entwickler! Und in andere Denkansätze zu Investieren, die Probleme einfacher lösen können, ist ein grundsätzlicher Wettbewerbsvorteil. Und weil noch nicht alle dies erkannt haben, packen Sie die Chance vor den anderen!
 

Wir bieten Hilfe für einen fundierten Einstieg in FP mit F#

Unser F# Kurs vermittelt die Denkweise des Funktionalen Programmierens (FP) von Grund auf, ohne zu sehr akademisch oder mathematisch zu werden. Die F# Programmiersprache wird praxisorientiert gelernt, immer aufbauend auf den Funktionalen Prinzipien, Schritt für Schritt. So lernt man von Kleinen der Funktionen bis ins Grosse der Module wie man per Komposition die Software Lösung entwickelt. Ich habe die Erfahrung in meinen F# Kursen gemacht, dass Senior Software Architekten und CTOs, bei einigen FP-Prinzipien die Köpfe geraucht haben (das ist stark positiv, denn das ist die Reaktion des Gehirns auf die neuen Denkweisen!) und dann gestaunt haben wie elegant man komplexe Dinge lösen kann, und nicht mehr warten konnten es gleich auszuprobieren. Zum Kurs Angebot      [1] “Why are C# programmers afraid of F# or functional languages in general?” 150115 https://dotnetkicks.com/stories/105569

Wettbewerbsvorteil F#

Sie wissen dass Funktionale Programmierung ein relevantes Thema in der Software Entwicklung ist, aber Sie haben bisher gewartet es auszuprobieren?

Ja C# bietet Funktionale Ansätze, wird aber niemals das bieten können, was eine vom Kern her echte Funktionale Sprache bietet.

Und genau dies macht den Unterschied, denn Werkzeuge prägen die Denkweise und Herangehensweise beim Lösen von Problemen. Ja genau, es geht um Problemlösungen, die F# Syntax ist nebensächlich und übrigens viel einfacher als C#. Die Denkweise beeinflusst die Architektur, den Design und vieles wird einfacher!

F# ist voll kompatibel mit der .NET Umgebung, sie müssen also nichts über Bord werfen, kein Risiko, ja Sie haben F# bereits seit 2010 auf Ihren Computern installiert im Visual-Studio. F# ist voll von Microsoft unterstützt, ist Open Source und Multiplatform!

Ich kenne F# seit 2009 und wende es seit 2011 fulltime für alles an. Davor C# seit .NET 1.1 und C++, PASCAL, ADA, LISP, C, Assembler. Ich habe Informatik studiert und mir mit 12 Jahren das Programmieren selbst beigebracht. Ich weiss wovon ich rede. Ich biete eine erfahrene sauber aufgebaute Einführung in die praxisnahe Funktionale Programmierung mit F# für .NET an.

Da ich selber von C# auf F# umgestiegen bin, kenne ich die Stolpersteine und räume diese aus dem Weg für einen glatten Einstieg. Ich denke nach meinem Kurs werden Sie nicht mehr zögern F# einzusetzen. Und ich denke, falls bei Ihnen schon jemand F# ausprobiert hat und zur Seite gelegt hat, weil man “das alles in C# auch machen kann“, dann liefere ich genau die nötigen fehlenden Facts. Das Zentrale ist nicht die Sprach Syntax von F# die offensichtlich anders ist, es ist die Denkweise und die Konzepte der Funktionalen Programmierung.

Und nein, es ist kein Hype, keine Bubble die bald platzen könnte, die Grundlagen der Funktionalen Programmierung wurden schon in den 30-er Jahren gelegt und mathematisch bewiesen! Und warum ist es dann heute so neu, dass man das jetzt lernen soll? Die Zeiten sind vorbei, wo ein Computer nur einen Prozessor hatte und Speicher ist heute massig vorhanden. Und um diese neuen Gegebenheiten bestens in Ihren Software Produkten nutzen zu können, ist die Funktionale Programmierung (FP) die ideale Methodik. Und an den Schulen und Universitäten wird es bisher leider nur kurz überflogen. Denn bisher wollte man auf dem Arbeitsmarkt ausschließlich Software Entwickler mit Kenntnissen in Objektorientierter Programmierung (OOP). Und F# kann übrigens auch OOP, wie gesagt voll kompatibel zu .NET. Also wird OOP nicht über Bord geworfen, sondern echtes FP kommt hinzu!

Und wie immer ist man zu beschäftigt, um Neues anzuwenden?

Are you too busy to improve?

Bild Referenz: https://hakanforss.wordpress.com/2014/03/10/are-you-too-busy-to-improve/

Ich sage es Ihnen, das ist es Wert! Wenn Sie Ihrer Firma einen Wettbewerbsvorteil verschaffen wollen und produktiver und effektiver, robuste Software Entwickeln wollen in der .NET Welt, dann ist das der beste Weg.

Und sollte ich Sie noch nicht ganz überzeugt haben, dann lesen Sie bitte was andere Anwender von namhaften Firmen zu F# sagen http://fsharp.org/testimonials/

Mehr zu den Vorzügen von F# können Sie auf meinem Deutschsprachigen Blog lesen http://FunctionalSoftware.NET/warum-fsharp/

Kompakte F# Schulungskurse

Vorsprung durch Wissen!
Es ist nicht genug zu wissen – man muss auch anwenden.
Es ist nicht genug zu wollen – man muss auch tun.
— Johann Wolfgang von Goethe
 

 



Sie wenden Flow Design in C# an?

Flow Design entspricht  eigentlich der Denkweise von Funktionaler Programmierung, es gibt Funktionen mit Input und Output, die Anzahl von Input und Output kann beliebig sein und damit man kann die Funktionen verbinden. Am besten stellt man sich das als eine Elektrische Verdrahtung vor. Die Daten fließen durch die Funktionen, werden also transformiert und nicht in einer Objekt-Daten-Kapsel mutiert, was es einfacher macht gedanklich den Überblick zu behalten, einfacher zu Testen ist und auch die Skalierbarkeit (Stichwort Multicore) ist so einfach möglich (ohne die Gefahr von Deadlocks). In F# wird ihnen auffallen, dass die ganzen Objekt-Konstrukte die man für Flow Design aufbauen muss, hinfällig werden und im Code am ehesten den Diagrammen entspricht. Die Verdrahtung (wiring) kann viel eleganter mit dem F# Pipe Operator (|>) gemacht werden.
Daten |> Validierung |> Auswertung
Der Datenfluss erfolgt in Pfeil |> Richtung. Man kann den Flow auch untereinander schreiben.
Daten
|> Validierung
|> Auswertung
So fließen die Daten durch die Funktion Validierung dann die Funktion Auswertung. Und ob alles auch zusammen passt, das sagt ihnen der Compiler bevor es evtl. zu Laufzeitfehlern kommt. Eine Cheat-Sheet zu Flow-Design findet sich hier.

Fazit

Wer Flow Design anwendet, kann sich viel Arbeit in der Codierung ersparen und gleichzeitig die Qualität (Korrektheit, Lesbarkeit, Wartbarkeit) des Codes erhöhen, wenn man diesen mit F# implementiert.

Videos zum Thema Funktionale Programmierung (FP)

Hier sind einige neue interessante und zum anders Denken anregende Videos zum Thema Funktionale Programmierung (FP). Warum sich jeder Software Entwickler mit FP befassen muss!

Weckruf – rüttelt an dem wie man bisher Software entwickelt(e).

Titel: Functional Programming: What? Why? When? Aussage: The Failure of State Autor: Robert C. Martin Titel: Programming in Interesting Times Aussage: YOUR PROGRAMMING LANGUAGE IS GOING TO DIE Autor: Russ Olsen Titel: One Hacker Way, a Rational Alternative to Agile Aussage: With Scrum we talk too much about code, instead of writing code. Uses the F***-word Autor: Erik Meijer Titel: Type Systems – The Good, Bad and Ugly Aussage: Not relying on type safety is unethical (if you have an SLA) Autor: Paul Snively and Amanda Laucher

   

Zeigt die Möglichkeiten von F#

Titel: FSLAB: DOING DATA SCIENCE WITH F# Aussage: How to get knowledge from data? Autor: Tomas Petricek Title: MBrace: large-scale programming in F# Aussage: Cloud Computing is easy with F# Autor: Eirik Tsarpalis