37
Czyli funkcyjny .NET Jakub Rusiłko F#

Czyli funkcyjny .NET Jakub Rusiłko

  • Upload
    velika

  • View
    37

  • Download
    0

Embed Size (px)

DESCRIPTION

F#. Czyli funkcyjny .NET Jakub Rusiłko. Plan prezentacji. Wstęp Co to jest programowanie funkcyjne C# vs F# Cechy języka F# Typy Currying i Partial Function Application OOP w F# Asynchroniczność w F#. Wstęp. Kim jestem? Dlaczego F# i co fajnego jest w programowaniu funkcyjnym?. - PowerPoint PPT Presentation

Citation preview

Page 1: Czyli funkcyjny .NET Jakub  Rusiłko

Czyli funkcyjny .NET

Jakub Rusiłko

F#

Page 2: Czyli funkcyjny .NET Jakub  Rusiłko

PLAN PREZENTACJI• Wstęp

• Co to jest programowanie funkcyjne

• C# vs F#

• Cechy języka F#

• Typy

• Currying i Partial Function Application

• OOP w F#

• Asynchroniczność w F#

Page 3: Czyli funkcyjny .NET Jakub  Rusiłko

WSTĘP• Kim jestem?

• Dlaczego F# i co fajnego jest w programowaniu funkcyjnym?

Page 4: Czyli funkcyjny .NET Jakub  Rusiłko

ZNIECHĘCAJĄCY KOD FUNKCYJNY((n.lisp_token_pos_guess is to)

((year))

((p.lisp_token_pos_guess is sym)

((pp.lisp_token_pos_guess is sym)

((cardinal))

((lisp_num_digits < 4.6)((year)) ((digits))))

((lisp_num_digits < 4.8)

((name < 2880)

((name < 1633.2)

((name < 1306.4)((cardinal))((year)))

((year)))

((cardinal)))

((cardinal)))))))))

Page 5: Czyli funkcyjny .NET Jakub  Rusiłko

POGRAMOWANIE FUNKCYJNE – KILKA DEFINICJI• Programowanie funkcyjne (z wikipedii) – filozofia i metodyka programowania będąca

odmianą programowania deklaratywnego, w której funkcje należą do wartości podstawowych, a nacisk kładzie się na wartościowanie (często rekurencyjnych) funkcji, a nie na wykonywanie poleceń.

• Programowanie funkcyjne jest jak opisywanie twojego zadania matematykowi. Programowanie imperatywne jest jak wydawanie instrukcji idiocie.

• Programowanie funkcyjne traktuje wykonanie programu jak ewaluację funkcji matematycznej i stara się unikać stanu oraz zmiennych.

Page 6: Czyli funkcyjny .NET Jakub  Rusiłko

PODZIAŁ JĘZYKÓW FUNKCYJNYCH• języki czysto funkcyjne - nie ma zmiennych, nie ma efektów ubocznych, leniwe

wartościowanie, we/wy musi się odbywać alternatywnym sposobem, jak na przykład monady (np. Haskell)

• języki mieszane - można stosować zmienne, tworzyć efekty uboczne, tradycyjne we/wy, mieszać styl funkcyjny z imperatywnym lub obiektowym, wartościowanie przeważnie zachłanne (np. Lisp, Clojure, Scheme, Erlang, Scala, F#)

Page 7: Czyli funkcyjny .NET Jakub  Rusiłko

KIEDY PROGRAMOWANIE FUNKCYJNE MOŻE OKAZAĆ CI SIĘ POMOCNE• Gdy masz trudności z przewidzeniem rezultatu zmian w swoim kodzie z powodu ukrytych

zależności i subtelności

• Gdy zdajesz sobie sprawę, że ciągle tworzysz te same wzorce i szablony poświęcając mało czasu na kluczowe i interesujące aspekty problemu

• Masz trudności z analizą swojego kodu i martwisz się tym, czy dany fragment zostanie wykonany we właściwej kolejności i przy odpowiednich warunkach

• Masz trudności z wyrażaniem abstrakcji, która ukrywa JAK kod ma się wykonać, a wyraża tylko CO chcesz osiągnąć

• Masz problemy z ogarnięciem kontroli nad kodem asynchronicznym

• Gdy kod zachowuje się inaczej na produkcji i inaczej podczas testów jednostkowych

Page 8: Czyli funkcyjny .NET Jakub  Rusiłko

F# - HISTORIA• Początki programowania funkcyjnego to Information Processing Language z 1956, a

potem Lisp w 1958

• Języki funkcyjne szybko zostały wyparte przez języki imperatywne jak Fortran (1957) czy COBOL (1959)

• W 1973 powstaje język ML. Jest on na tyle dobry, że powstaje wiele języków pochodnych jak Standard ML, Caml i OCaml, który łączy styl funkcyjny z obiektowo zorientowanym stylem imperatywnym

• W 2005 powstaje F#, który w dużej mierze jest .NETową implemantacją OCamla.

Page 9: Czyli funkcyjny .NET Jakub  Rusiłko

CECHY JĘZYKA F#• Statycznie typowany – kompilator zna typy zmiennych i funkcji w momencie kompilacji

• Silnie typowany – zmienne nie zmieniają swojego typu

• F# nie przeprowadza automatycznego rzutowania typów (tak jak C# czy VB), trzeba rzutować explicite

• Zachęca do tworzenia kodu z użyciem zmiennych niemutowalnych, ale pozwala używać zmiennych mutowalnych, jeśli jest to konieczne

• Pozwala na korzystanie z bibliotek napisanych w innych językach rodziny .NET i bez problemu się z nimi łączy

• Łączy zalety języka funkcyjnego z obiektowym

• Zamiast nawiasów klamrowych { i } stosuje wcięcia linii

• Wnioskowanie typów (Type Inference) – analogicznie do var w C#

Page 10: Czyli funkcyjny .NET Jakub  Rusiłko

CECHY JĘZYKA F#• Nie używamy słowa return – zwrot wartości z funkcji jest automatyczny

• Unit zamiast void

• Automatyczna generalizacja

• Kolejność plików w projekcie ma znaczenie

Page 11: Czyli funkcyjny .NET Jakub  Rusiłko

PROSTY PROGRAM W F#open System

let a = 2

Console.WriteLine a

Page 12: Czyli funkcyjny .NET Jakub  Rusiłko

PROSTY PROGRAM W C#using System;namespace ConsoleApplication1{ class Program { static int a() { return 2; } static void Main(string[] args) { Console.WriteLine(a); } }}

Page 13: Czyli funkcyjny .NET Jakub  Rusiłko

F# INTERACTIVE• Interaktywna konsola wspomagająca programowanie

• DEMO

Page 14: Czyli funkcyjny .NET Jakub  Rusiłko

TYPY W F#• Typy proste (int, char, float, …)

• Typy z bibliotek .NET

• Typy właściwe dla F#

Page 15: Czyli funkcyjny .NET Jakub  Rusiłko

TUPLES (KROTKI)

1. let t1 = (2,3)2. let t2 = ("hello",42)3. let t3 = (42,true,"hello")

4. let z = 1,true,"hello",3.14 // "construct"5. let z1,z2,z3,z4 = z // "deconstruct"6. let _,z5,_,z6 = z // ignore 1st and 3rd elements

7. let first = fst t18. let second = snd t1

Page 16: Czyli funkcyjny .NET Jakub  Rusiłko

Tuple<U, T> Swap<T, U>(Tuple<T, U> t){

return new Tuple<U, T>(t.Item2, t.Item1);}

let swap (x,y) = (y,x)

PROSTA ZAMIANA MIEJSCAMI W KROTCE (TUPLE) W F# VS C#

F#

C#

Page 17: Czyli funkcyjny .NET Jakub  Rusiłko

RECORDS (REKORDY)1. type ComplexNumber = { real: float; imaginary: float }2. type GeoCoord = { lat: float; long: float }

3. let myGeoCoord = { lat = 1.1; long = 2.2 } // "construct"4. let { lat=myLat; long=myLong } = myGeoCoord // "deconstruct”5. let x = myGeoCoord.lat

6. let g1 = {lat=1.1; long=2.2}7. let g2 = {g1 with lat=99.9} // create a new one

Page 18: Czyli funkcyjny .NET Jakub  Rusiłko

DISCRIMINATED UNION TYPE• Typ będący sumą kilku typówtype IntOrBool =

| I of int

| B of bool

type Person = {first:string; last:string} // define a record type type IntOrBool = I of int | B of bool

type MixedType = | Tup of int * int // a tuple | P of Person // use the record type defined above | L of int list // a list of ints | U of IntOrBool // use the union type defined above

Page 19: Czyli funkcyjny .NET Jakub  Rusiłko

DISCRIMINATED UNION VS ENUM ORAZ PATTERN MATCHING• type SizeUnion = Small | Medium | Large //

union• type ColorEnum = Red=0 | Yellow=1 | Blue=2 //

enum

• DEMO

Page 20: Czyli funkcyjny .NET Jakub  Rusiłko

NULL I OPTION TYPE• W czystym F# nie ma pojęcia nulla (istnieje tylko w celu kompatybilności z .net)

• Aby oznaczyć brak wartości stosujemy Option Type

• Podobne do Nullable w C# z tą różnicą, że Option można użyć z dowolnym typem (również na typach referencyjnych, klasach, itp.)

type Option<'a> = | Some of 'a | None

• DEMO

Page 21: Czyli funkcyjny .NET Jakub  Rusiłko

UNITS OF MEASURE• [<Measure>] type m• [<Measure>] type sec• [<Measure>] type kg

• let distance = 1.0<m> • let time = 2.0<sec> • let speed = 2.0<m/sec> • let acceleration = 2.0<m/sec^2> • let force = 5.0<kg m/sec^2>

• [<Measure>] type N = m/sec^2

Page 22: Czyli funkcyjny .NET Jakub  Rusiłko

KOLEKCJE - LISTY

let numbers = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10]let numbers2 = 1 :: 2 :: 3 :: 4 :: []let numbers3 = [1 .. 5]let numbers4 = [1 .. 2 .. 10]let numbers5 = List.init 10 (fun i -> i)• DEMO

Page 23: Czyli funkcyjny .NET Jakub  Rusiłko

KOLEKCJE - SEKWENCJE• Są podobne do list z tą różnicą, że ich wartości są wyliczane na bieżąco, gdy są

potrzebne (leniwie - LAZY)

let sequence1 = seq { 1 .. 10 }

let sequence2 = seq {10 .. -1 .. 0}

let sequence3 = seq { for a in 1 .. 10 do yield a, a*a, a*a*a }• DEMO

Page 24: Czyli funkcyjny .NET Jakub  Rusiłko

NIEZMIENNOŚĆ (IMMUTABILITY)• Słowo kluczowe let definiuje wartość

• Value Binding – (wiązanie wartości) pozwala powiązać wartość z symbolem

• Niezmienność wymusza inne spojrzenie na problemy

• Każda kolejna operacja na zadeklarowanej wartości tworzy nową wartość (nie zmienia starej) – analogia do typu string z C#

• Rekurencja zamiast pętli

• Niezmienność zachęca do używania pojedynczych wyrażeń zamiast sekwencji poleceń sprawiając, że program jest bardziej deklaratywny

Przykład w C#:

var res = ImmutableList.Empty<int>().Add(1).Add(3).Add(5).Add(7); //Sytem.Collections.Immutable (.NET 4.5)

Page 25: Czyli funkcyjny .NET Jakub  Rusiłko

FUNKCJE JAKO WARTOŚCI• Funkcja jest wartością i może być użyta w każdej sytuacji, w której możemy użyć

zwykłego int’a czy string’a (First-class functions), każda funkcja ma typ (w C# używamy do tego delegatów, w F# typ jest właściwością samej funkcji)

• W szczególności funkcja może być parametrem do innej funkcji lub wynikiem wyjściowym funkcji – funkcje wyższego rzędu (Higher-order functions)

• DEMO (agregacja)

Page 26: Czyli funkcyjny .NET Jakub  Rusiłko

SYGNATURA FUNKCJI• int -> int -> int

• int -> unit

• unit -> string

• int -> (unit -> string)

• 'a list -> 'a

• ('a -> bool) -> 'a list -> 'a list

• DEMO

Page 27: Czyli funkcyjny .NET Jakub  Rusiłko

CURRYING• Ale dlaczego sygnatury funkcji nie rozróżniają między parametrami a typem wyjściowym?

• CURRYING – rozbijanie wieloargumentowych funkcji na mniejsze jedno-parametrowe funkcje

• Haskell Curry – matematyk, który przyczynił się do rozwoju programowania funkcyjnego

• int -> int -> int jest tak naprawdę połączeniem więcej niż jednej funkcji

• Nie musimy się tym martwić, kompilator robi to za nas automatycznie

• DEMO

Page 28: Czyli funkcyjny .NET Jakub  Rusiłko

PARTIAL FUNCTION APPLICATION• Dzięki curryingowi wywołanie funkcji z mniejszą ilością parametrów, niż to wynika z

definicji funkcji, jest dozwolonym działaniem

• Wywołanie funkcji z n-początkowymi parametrami zwróci nową funkcję przyjmującą pozostałe (z oryginalnej funkcji) parametry

• Właściwość ta jest jednym z najważniejszych narzędzi programowania funkcyjnego

• DEMO

Page 29: Czyli funkcyjny .NET Jakub  Rusiłko

KILKA CIEKAWYCH OPERATORÓW• |> - forward pipe operator – przekazuje rezultat operacji po lewej stronie do

funkcji po prawej stronie

• <| - backward pipe operator

• >> - forward composition operator - złożenie funkcji

• << - backward composition operator - złożenie funkcji (w odwrotnej kolejności)

• DEMO

Page 30: Czyli funkcyjny .NET Jakub  Rusiłko

OBIEKTOWY F#• Pozwala zaimplementować algorytmy obiektowe 1 do 1

• Ułatwia integrację z .NETem

• Dla początkujących może przysłonić korzyści płynące z programowania czysto funkcyjnego

• Nie współpracuje dobrze z funkcjami wyższego poziomu oraz z wnioskowaniem typów

• DEMO

Page 31: Czyli funkcyjny .NET Jakub  Rusiłko

OBJECT EXPRESSIONS• Pozwala implementować interfejs w locie bez potrzeby tworzenia klasy

let makeResource name = { new System.IDisposable with member this.Dispose() = printfn "%s disposed" name }

Page 32: Czyli funkcyjny .NET Jakub  Rusiłko

ASYNCHRONOUS WORKFLOWS• DEMO

Page 33: Czyli funkcyjny .NET Jakub  Rusiłko

MESSAGES AND AGENTS• MailboxProcessor implementuje podejście bazujące na agentach i wiadomościach (kolejki

wiadomości)

• Działa w osobnym wątku

• Pozwala łatwo zarządzać dzielonymi zasobami bez zakleszczeń

• Umożliwia łatwe rozdzielenie odpowiedzialności poprzez tworzenie osobnych agentów obsługujących różne rzeczy

• DEMO

Page 34: Czyli funkcyjny .NET Jakub  Rusiłko

QUICKSORT C#public class QuickSortHelper { public static List<T> QuickSort<T>(List<T> values) where T : IComparable { if (values.Count == 0) { return new List<T>(); } T firstElement = values[0]; var smallerElements = new List<T>(); var largerElements = new List<T>(); for (int i = 1; i < values.Count; i++) { var elem = values[i]; if (elem.CompareTo(firstElement) < 0) { smallerElements.Add(elem); } else {largerElements.Add(elem);} } var result = new List<T>(); result.AddRange(QuickSort(smallerElements.ToList())); result.Add(firstElement); result.AddRange(QuickSort(largerElements.ToList())); return result; } }

Page 35: Czyli funkcyjny .NET Jakub  Rusiłko

QUICKSORT F# - W STYLU FUNKCYJNYMlet rec quicksort list =

match list with

| [] -> []

| firstElem::otherElements ->

let smallerElements = otherElements |> List.filter (fun e -> e < firstElem) |> quicksort

let largerElements = otherElements |> List.filter (fun e -> e >= firstElem) |> quicksort

List.concat [smallerElements; [firstElem]; largerElements]

let rec quicksort2 = function

| [] -> []

| first::rest ->

let smaller,larger = List.partition ((>=) first) rest

List.concat [quicksort2 smaller; [first]; quicksort2 larger]

Page 36: Czyli funkcyjny .NET Jakub  Rusiłko

ŹRÓDŁA

• http://pl.wikipedia.org/wiki/Programowanie_funkcyjne

• http://fsharpforfunandprofit.com/

• http://en.wikibooks.org/wiki/F_Sharp_Programming

• Real-World Functional Programming, Tomas Petricek i Jon Skeet, Manning Publications, 2010

Page 37: Czyli funkcyjny .NET Jakub  Rusiłko

KONIEC