Wolna monada IO
Co to znaczy, że monada jest wolna? Możemy podzielić monady na dwa typy: takie które wykonują się od razu (np. monada Result
) oraz takie, które trzeba wykonać specjalną funkcją po zbudowaniu (np. monada State
).
Wolne monady to drugie. Dokładniej rzecz biorąc jest to dużo bardziej skomplikowane, sam ledwo rozumiem zasady działania kategorii wolnych monad. Cel jest taki, że dopóki nie uruchomimy monady, to możemy ją bezkarnie budować i ani kawałek jej kodu nie zostanie wykonany.
Wolne monady mają więc zalety. Między innymi będzie to możliwość powtórzenia wykonania. Np. monadę stanu budujemy raz, a potem możemy wywoływać wiele razy z różnym stanem.
Teraz zbudujemy sobie wolną monadę IO
, która w funkcyjny sposób pozwoli nam komunikowac się ze światem.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: |
|
Przygotowaliśmy Monadę zawierającą kilka pożądanych przez nas operacji. W zasadzie dopóki nie napiszemy interpretera dla tej monady, to zbudowanie jej nie będzie miało żadnych efektów.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: |
|
Napisaliśmy program, który wczytuje zawartość pliku na podstawie jego nazwy od użytkownika, a następnie dopisuje linijkę. Teraz utworzymy interpreter naszej monady.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: |
|
Kiedy uruchomimy ten interpreter na naszym programie to wtedy po kolei będziemy wykonywać określone czynności.
Pure
oznacza po prostu jakąś wartość. PutStrLn
niesie ze sobą string do wypisania na ekran oraz będzie zwracać ()
do funkcji którą przekazuje do bind
, a na koniec dostajemy kolejne IO
, czyli pewną kontynuację do wykonania. Tworzymy taki łańcuch IO
, który krok po kroku wykonujemy. Pozostałem GetStrLn
, ReadFile
i WriteFile
zachowują się bardzo podobnie.
Nie będziemy już mieli zadań, a zamiast tego porozmawiamy sobie o monadzie Async
, którą można nieco potraktować jako wolną monadę do asynchronicznych operacji.
| Pure of 'a
| PutStrLn of string * (unit -> IO<'a>)
| GetStrLn of (string -> IO<'a>)
| ReadFile of name: string * (string -> IO<'a>)
| WriteFile of name: string * contents: string * (unit -> IO<'a>)
Full name: Io_monad.IO<_>
val string : value:'T -> string
Full name: Microsoft.FSharp.Core.Operators.string
--------------------
type string = System.String
Full name: Microsoft.FSharp.Core.string
Full name: Microsoft.FSharp.Core.unit
Full name: Io_monad.ioBind
type IOBuilder =
new : unit -> IOBuilder
member Bind : m:IO<'b> * f:('b -> IO<'c>) -> IO<'c>
member Return : x:'d -> IO<'d>
member Zero : x:'a -> IO<unit>
Full name: Io_monad.IOBuilder
--------------------
new : unit -> IOBuilder
Full name: Io_monad.IOBuilder.Return
Full name: Io_monad.IOBuilder.Bind
Full name: Io_monad.IOBuilder.Zero
Full name: Io_monad.io
Full name: Io_monad.pureNext
Full name: Io_monad.putStrLn
Full name: Io_monad.getStrLn
Full name: Io_monad.readFile
Full name: Io_monad.writeFile
Full name: Io_monad.program
Full name: Io_monad.interpret
Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printfn
static member BackgroundColor : ConsoleColor with get, set
static member Beep : unit -> unit + 1 overload
static member BufferHeight : int with get, set
static member BufferWidth : int with get, set
static member CapsLock : bool
static member Clear : unit -> unit
static member CursorLeft : int with get, set
static member CursorSize : int with get, set
static member CursorTop : int with get, set
static member CursorVisible : bool with get, set
...
Full name: System.Console
static member AppendAllLines : path:string * contents:IEnumerable<string> -> unit + 1 overload
static member AppendAllText : path:string * contents:string -> unit + 1 overload
static member AppendText : path:string -> StreamWriter
static member Copy : sourceFileName:string * destFileName:string -> unit + 1 overload
static member Create : path:string -> FileStream + 3 overloads
static member CreateText : path:string -> StreamWriter
static member Decrypt : path:string -> unit
static member Delete : path:string -> unit
static member Encrypt : path:string -> unit
static member Exists : path:string -> bool
...
Full name: System.IO.File
System.IO.File.ReadAllText(path: string, encoding: System.Text.Encoding) : string
System.IO.File.WriteAllText(path: string, contents: string, encoding: System.Text.Encoding) : unit