F# a matematyka

Czas czytania ~ 200 sekund

Jest taki całkiem znany żart:

Profesorowi przeciekał kran, więc wezwał hydraulika. Hydraulik przez 10 minut podłubał przy kranie i policzył 100 zł. Profesor się strasznie zdenerwował, że on, osoba wykształcona, zarabia grosze, a hydraulik za chwilę roboty policzył sobie spore pieniądze. Hydraulik na to:

– Wie pan co… U nas w spółdzielni szukają teraz pracowników. Zgłosi się pan i będzie pan pracował jako hydraulik. Tylko niech pan nie mówi, że pan jest profesor. Najlepiej będzie, jeśli pan powie że pan skończył 7 klas podstawówki.

Profesor tak właśnie zrobił i pracował przez jakiś czas, ale przyszło zarządzenie kierownictwa, że wszyscy pracownicy mają mieć skończoną podstawówkę. Więc profesor, chcąc nie chcąc, musiał iść na kurs razem z kolegami z pracy, żeby się nie wydał kłamstwo.

Na pierwszych zajęciach nauczyciel wziął profesora do tablicy każe policzyć pole koła. Profesor wypisał bardzo zgrabną całkę, ale wynik mu wyszedł ujemny.

Myśli, myśli, i nagle słyszy szept z pierwszej ławki:

– Zmień granice całkowania…

Źródło (matematyka.pl)

Jeśli czytasz blog techniczny, to całkiem możliwe, że w szkole lubiłeś / lubiłaś przedmioty ścisłe. Analogii do matematyki w naszej pracy jest sporo. Pierwsze, co przychodzi do głowy: co ma wspólnego takie równanie:

codecogseqn

Z takim fragmentem kodu:

public IEnumerable<int> GetIdentifiers(bool membersOnly)
{
     if(membersOnly)
     {
         return _context.Where(m => m.IsMember).Select(m => m.Id);
     }
     else
     {
         return _context.Select(m => m.Id);
     }
}

W obu przypadkach można coś uprościć. W pierwszym przypadku jest to wyłączanie wspólnego czynnika przed nawias, w drugim refactoring.

Prawdopodobnie najbardziej inspirowane matematyką są języki funkcyjne. Oto kilka przykładów analogii, jakie można znaleźć pisząc kod w F#.

Pattern matching

Funkcje nieciągłe zapisywało się zawsze w zeszycie klamrą. Przykładowo funkcja Heaviside’a wygląda tak:

bas

W F# funkcję taką można zapisać używając mechanizmu pattern matchingu i będzie to wyglądało tak:

let H = fun n ->
            match n with
            | 0 -> 0.5
            | _ when n < 0 -> 0.0
            | _ when n > 0 -> 1.0

Sam mechanizm daje znacznie większe możliwości niż definiowanie funkcji, ale pewne podobieństwo można zaobserwować.

Operatory wbudowane w język

Przestrzeń nazw FSharp.Core.Operators zawiera sporo operacji matematycznych, których możemy używać out of the box, bez konieczności załączania usingów, instancjonowania klas, czy wywoływania metod statycznych (klasa Math w .NET). Czystość kodu w przykładach poniżej mówi sama za siebie:

let csc = fun x -> 1.0 / sin x
let sin2 = fun x -> 2.0 * sin x * cos x
let tan2 = fun x -> 2.0 * tan x / (1.0 - tan x ** 2.0)

Kompozycja funkcji

Mamy w matematyce coś takiego jak funkcje złożone. Złożenie funkcji g(x) i f(x) to nic innego jak g(f(x)). Dla przykładu złożenie dwóch funkcji:

adw

Możemy zapisać w F# tak:

let f = fun x -> log x
let g = fun u -> 3.0 * u ** 2.0 + u - 1.0
let h = f >> g

Po najechaniu kursorem na operator kompozycji funkcji pojawia się podpowiedź, że funkcja po lewej stronie operatora zostanie wykonana jako pierwsza.

Bramki logiczne

Tabele prawdy, czyli kombinacje wyjść funkcji w zależności od tego, jakie wartości logiczne przyjmują wejścia. Możemy to znowu zapisać przy pomocy pattern matchingu, ale nie musimy obsługiwać wszystkich kombinacji. Znak specjalny _ oznacza “pozostałe przypadki”. Dodatkowo, podobnie jak na studiach z jednych bramek logicznych można było tworzyć inne, przekazując wyjście do wejścia, tak też w F# wynik jednych funkcji można przekazywać do innych za pomocą operatora pipe forward.

let neg = fun x -> not x
let xor = fun x y -> match x,y with
                    | true, false -> true
                    | false, true -> true
                    | _ -> false

let xnor = fun x y -> xor x y |> neg

Jednostki miary

Dla fizyków też się coś znajdzie. Wartości numeryczne mogą mieć skojarzone ze sobą jednostki miary. Co więcej, jedne jednostki mogą być pochodnymi innych, tak, jak w fizyce Volty można wyliczyć z Ohmów i Amperów. Kompilator znając takie reguły może nas prowadzić za rękę przy trudniejszych obliczeniach fizycznych 

[<Measure>] type O
[<Measure>] type A
[<Measure>] type V = O*A

let cur = 3<A>
let res = 10<O>
let volt = res * cur

let isEqual = volt - 5<V> = 25<V>
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s