Podczas przygotowywania mojego warsztatu na GirlzCamp postanowiłem napisać sobie kilka monad w F#, w tym spróbować napisać transformator monad (co w ogólności mi się nie udało). Podczas moich zmagań natrafiłem na bibliotekę FSharpPlus, która jest mega!!
Przede wszystkim, jednym z większych problemów z jakimi się borykałem to sprawa operatora bind >>=. W Haskellu, dzięki klasom typów, można używać tego operatora do wszystkich monad, które instancjonują klasę Monad. W F# jest to nieco trudniejsze.
Okazuje się, że F# ma dwa typy generycznych argumentów typów. Najczęściej używany to 'T (z apostrofem), czyli typy ogólnie generyczne, zachowujące się tak jak generyki .NETowe. Ale jest jeszcze drugi typ - ^T (z daszkiem), który określa generyczny typ, rozwiązywany w trakcie kompilacji. Może być użyty tylko dla funkcji, które są inline i podczas kompilacji taka funkcja jest zastępowana na wywołanie konretnej funkcji, być może specyficznej dla danego typu.
Odpowiednie użycie funkcji inline i tych argumentów typowych rozwiązywanych w trackie kompilacji, pozwala na utworzenie generycznego operatora >>=, którego można używać dla każdej monady, pod warunkiem, że jej typ monadyczny zawiera
static member (>>=) : '``Monad<'T>`` -> ('T -> '``Monad<'U>``) -> '``Monad<'U>``
Także okazuje się, że F# pozwala na więcej niż by się na pierwszy rzut oka wydawało, ale składnia do tego jest strasznie nieintuicyjna.
W bibliotece FSharpPlus znajdziemy definicje kilku poręcznych funkcji oraz gotowych monad.
- result x- funkcja o znaczeniu- return, które w F# jest słowem kluczowym
- (>>=) x f- bind
- 
    map f x- dlaxbędącego Functorem, aplikujemy funkcjęfdo wartości w środkuxnp:let h = map ((+) 2) (Some 3) //h = Some 5 
- monad { }- środowisko do pracy z każdą monadą
- (<*>) : f<'a -> 'b> -> f<'a> -> f<'b>- gdzie- fto pewien Functor
- Implementacja MonadiFunctordla wbudowanych typówOption,Result,Choice
- Monady State,Writer,Reader,Contoraz ich transformatory
Więcej inormacji znajdziecie w repozytorium na GitHubie, aczkolwiek, ze względu na to, że spora część tej biblioteki to nieziemskie obejścia, jej kod jest mało czytelny.
Nie mniej jednak jesteśmy w stanie napisać coś takiego (przykład poniżej). Korzystanie z biblioteki wymaga dużej ilości adnotacji typów, żeby kompilator nie narzekał, więc nie jestem pewny czy będę ją wykorzystywał w projektach. Mam nadzieję, że dyskusja o wprowadzeniu klas typów do F# posunie się niedługo do przodu i zobaczymy używalne rozwiązanie.
