1 / 37

Czyli funkcyjny .NET Jakub Rusiłko

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?.

velika
Download Presentation

Czyli funkcyjny .NET Jakub Rusiłko

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. F# Czyli funkcyjny .NET Jakub Rusiłko

  2. Plan prezentacji • Wstęp • Co to jest programowanie funkcyjne • C# vs F# • Cechy języka F# • Typy • Currying i PartialFunction Application • OOP w F# • Asynchroniczność w F#

  3. Wstęp • Kim jestem? • Dlaczego F# i co fajnego jest w programowaniu funkcyjnym?

  4. Zniechęcający kod funkcyjny ((n.lisp_token_pos_guessis to) ((year)) ((p.lisp_token_pos_guessissym) ((pp.lisp_token_pos_guessissym) ((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)))))))))

  5. 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.

  6. 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#)

  7. 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

  8. 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.

  9. 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 (TypeInference) – analogicznie do var w C#

  10. 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

  11. Prosty program w F# openSystem let a =2 Console.WriteLine a

  12. Prosty program w C# using System; namespace ConsoleApplication1 { classProgram { staticint a() { return2; } staticvoidMain(string[] args) { Console.WriteLine(a); } } }

  13. F# Interactive • Interaktywna konsola wspomagająca programowanie • DEMO

  14. Typy w F# • Typy proste (int, char, float, …) • Typy z bibliotek .NET • Typy właściwe dla F#

  15. Tuples (Krotki) • let t1 = (2,3) • lett2 = ("hello",42) • lett3 = (42,true,"hello") • let z =1,true,"hello",3.14// "construct" • let z1,z2,z3,z4 = z // "deconstruct" • let _,z5,_,z6 = z // ignore 1st and 3rd elements • letfirst=fst t1 • letsecond=snd t1

  16. Prosta zamiana miejscami w Krotce (Tuple) w F# vs C# F# C# Tuple<U, T> Swap<T, U>(Tuple<T, U> t) { returnnewTuple<U, T>(t.Item2, t.Item1); } letswap (x,y) = (y,x)

  17. Records (rekordy) • typeComplexNumber= { real: float; imaginary: float } • typeGeoCoord= { lat: float; long: float } • letmyGeoCoord= { lat=1.1; long =2.2 } // "construct" • let { lat=myLat; long=myLong } =myGeoCoord// "deconstruct” • let x =myGeoCoord.lat • let g1 = {lat=1.1; long=2.2} • let g2 = {g1 withlat=99.9} // create a new one

  18. Discriminated Union Type • Typ będący sumą kilku typów typeIntOrBool= | I ofint | B ofbool type Person = {first:string; last:string} // define a record type typeIntOrBool= I ofint | B ofbool typeMixedType= | Tupofint*int// a tuple | P of Person // use the record type defined above | L ofint list // a list of ints | U ofIntOrBool// use the union type defined above

  19. Discriminated Union vs enum oraz PatternMatching • typeSizeUnion= Small | Medium | Large // union • typeColorEnum= Red=0 | Yellow=1 | Blue=2// enum • DEMO

  20. 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>= | Someof'a | None • DEMO

  21. Units of measure • [<Measure>] type m • [<Measure>] type sec • [<Measure>] type kg • letdistance=1.0<m> • lettime=2.0<sec> • letspeed=2.0<m/sec> • letacceleration=2.0<m/sec^2> • letforce=5.0<kg m/sec^2> • [<Measure>] type N = m/sec^2

  22. Kolekcje - Listy letnumbers = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10] letnumbers2=1::2::3::4:: [] letnumbers3 = [1..5] letnumbers4= [1..2..10] letnumbers5 =List.init10 (fun i -> i) • DEMO

  23. 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 in1..10doyield a, a*a, a*a*a } • DEMO

  24. Niezmienność (Immutability) • Słowo kluczowe letdefiniuje 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#: varres =ImmutableList.Empty<int>().Add(1).Add(3).Add(5).Add(7); //Sytem.Collections.Immutable (.NET 4.5)

  25. 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-classfunctions), 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)

  26. Sygnatura FUnkcji • int -> int -> int • int -> unit • unit -> string • int -> (unit -> string) • 'a list -> 'a • ('a -> bool) -> 'a list -> 'a list • DEMO

  27. Currying • Ale dlaczego sygnatury funkcji nie rozróżniają między parametrami a typem wyjściowym? • CURRYING– rozbijanie wieloargumentowych funkcji na mniejsze jedno-parametrowe funkcje • HaskellCurry – 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

  28. Partialfunctionapplication • Dzięki curryingowiwywoł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

  29. Kilka ciekawych operatorów • |> - forwardpipe operator – przekazuje rezultat operacji po lewej stronie do funkcji po prawej stronie • <| - backwardpipe operator • >> - forwardcomposition operator - złożenie funkcji • << - backwardcomposition operator - złożenie funkcji (w odwrotnej kolejności) • DEMO

  30. 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

  31. Object expressions • Pozwala implementować interfejs w locie bez potrzeby tworzenia klasy letmakeResourcename= { newSystem.IDisposable withmemberthis.Dispose() =printfn"%s disposed" name }

  32. AsynchronousWorkflows • DEMO

  33. Messages and Agents • MailboxProcessorimplementuje 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

  34. Quicksort C# publicclassQuickSortHelper { publicstaticList<T> QuickSort<T>(List<T> values) whereT : IComparable { if (values.Count==0) { returnnewList<T>(); } T firstElement=values[0]; varsmallerElements=newList<T>(); varlargerElements=newList<T>(); for (int i =1; i < values.Count; i++) { varelem=values[i]; if (elem.CompareTo(firstElement) <0) { smallerElements.Add(elem); } else {largerElements.Add(elem);} } varresult=newList<T>(); result.AddRange(QuickSort(smallerElements.ToList())); result.Add(firstElement); result.AddRange(QuickSort(largerElements.ToList())); returnresult; } }

  35. Quicksort F# - w stylu funkcyjnym letrecquicksort list = match list with | [] -> [] | firstElem::otherElements-> letsmallerElements=otherElements|>List.filter (fun e -> e <firstElem) |>quicksort letlargerElements=otherElements|>List.filter (fun e -> e >=firstElem) |> quicksort List.concat [smallerElements; [firstElem]; largerElements] letrec quicksort2 =function | [] -> [] | first::rest-> letsmaller,larger=List.partition ((>=) first) rest List.concat [quicksort2 smaller; [first]; quicksort2 larger]

  36. Ź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, TomasPetricek i Jon Skeet, Manning Publications, 2010

  37. KONIEC

More Related