FSharpPlus


Free<'Functor<'T>, 'T>

This type is an implementation of the Free Monad which is generic to any Functor.

The Free Monad is used typically to describe a pure program at high level and separately write different interpreters for it.

Related Types

Examples

Free monad-interpreter in F# from Mark Seemann's blog but encoded with Free.

#r @"nuget: FSharpPlus"
open System
open FSharpPlus
open FSharpPlus.Data


type CommandLineInstruction<'t> =
    | ReadLine  of (string -> 't)
    | WriteLine of  string  * 't
with static member Map (x, f) =
        match x with
        | ReadLine   g     -> ReadLine  (f << g)
        | WriteLine (s, g) -> WriteLine (s, f g)

let readLine    = Free.liftF (ReadLine id)
let writeLine s = Free.liftF (WriteLine (s, ()))


let rec interpretCommandLine = Free.run >> function
    | Pure x -> x
    | Roll (ReadLine      next)  -> Console.ReadLine () |> next |> interpretCommandLine
    | Roll (WriteLine (s, next)) ->
        Console.WriteLine s
        next |> interpretCommandLine

let rec readQuantity = monad {
    do! writeLine "Please enter number of diners:"
    let! l = readLine
    match tryParse l with
    | Some dinerCount -> return dinerCount
    | None ->
        do! writeLine "Not an integer."
        return! readQuantity }

let rec readDate = monad {
    do! writeLine "Please enter your desired date:"
    let! l = readLine
    match DateTimeOffset.TryParse l with
    | true, dt -> return dt
    | _ ->
        do! writeLine "Not a date."
        return! readDate }

let readName = monad {
    do! writeLine "Please enter your name:"
    return! readLine }
 
let readEmail = monad {
    do! writeLine "Please enter your email address:"
    return! readLine }


type Reservation = {
    Date : DateTimeOffset
    Name : string
    Email : string
    Quantity : int }
    with static member Create (Quantity, Date, Name, Email) = { Date = Date; Name = Name; Email = Email; Quantity = Quantity }

let readReservationRequest =
    curryN Reservation.Create
    <!> readQuantity
    <*> readDate
    <*> readName
    <*> readEmail



let mainFunc () =
    readReservationRequest
    >>= (writeLine << (sprintf "%A"))
    |> interpretCommandLine
    0

Recommended reading

namespace System
namespace FSharpPlus
namespace FSharpPlus.Data
't
union case CommandLineInstruction.ReadLine: (string -> 't) -> CommandLineInstruction<'t>
Multiple items
val string: value: 'T -> string

--------------------
type string = String
union case CommandLineInstruction.WriteLine: string * 't -> CommandLineInstruction<'t>
Multiple items
module Map from FSharpPlus
<summary> Additional operations on Map&lt;'Key, 'Value&gt; </summary>

--------------------
module Map from Microsoft.FSharp.Collections

--------------------
type Map<'Key,'Value (requires comparison)> = interface IReadOnlyDictionary<'Key,'Value> interface IReadOnlyCollection<KeyValuePair<'Key,'Value>> interface IEnumerable interface IStructuralEquatable interface IComparable interface IEnumerable<KeyValuePair<'Key,'Value>> interface ICollection<KeyValuePair<'Key,'Value>> interface IDictionary<'Key,'Value> new: elements: ('Key * 'Value) seq -> Map<'Key,'Value> member Add: key: 'Key * value: 'Value -> Map<'Key,'Value> ...

--------------------
new: elements: ('Key * 'Value) seq -> Map<'Key,'Value>
val x: CommandLineInstruction<'a>
val f: ('a -> 'b)
val g: (string -> 'a)
val s: string
val g: 'a
val readLine: Free<CommandLineInstruction<string>,string>
Multiple items
module Free from FSharpPlus.Data
<summary> Basic operations on Free Monads </summary>

--------------------
type Free<'functor<'t>,'t> = | Pure of 't | Roll of obj static member (<*>) : f: Free<'Functor<'T->'U>,('T -> 'U)> * x: Free<'Functor<'T>,'T> -> Free<'Functor<'U>,'U> (requires member Map and member Map and member Map and member Map and member Map) static member (>>=) : x: Free<'Functor<'T>,'T> * f: ('T -> Free<'Functor<'U>,'U>) -> Free<'Functor<'U>,'U> (requires member Map and member Map and member Map) static member Delay: x: (unit -> Free<'Functor<'T>,'T>) -> Free<'Functor<'T>,'T> static member Return: x: 'a -> Free<'b,'a>
val liftF: x: 'Functor<'T> -> Free<'Functor<'T>,'T> (requires member Map and member Map)
<summary> Lift any Functor into a Free structure. </summary>
val id: x: 'T -> 'T
val writeLine: s: string -> Free<CommandLineInstruction<unit>,unit>
val interpretCommandLine: (Free<CommandLineInstruction<unit>,unit> -> unit)
val run: f: Free<'Functor<'T>,'T> -> Choice<'T,'Functor<Free<'Functor<'T>,'T>>> (requires member Map)
Multiple items
union case Free.Pure: 't -> Free<'functor<'t>,'t>

--------------------
active recognizer Pure: Choice<'a,'b> -> Choice<'a,'b>
val x: unit
Multiple items
val Roll: f: 'Functor<Free<'Functor<'T>,'T>> -> Free<'Functor<'T>,'T> (requires member Map)

--------------------
active recognizer Roll: Choice<'a,'b> -> Choice<'a,'b>
val next: (string -> Free<CommandLineInstruction<unit>,unit>)
type Console = static member Beep: unit -> unit + 1 overload static member Clear: unit -> unit static member GetCursorPosition: unit -> struct (int * int) static member MoveBufferArea: sourceLeft: int * sourceTop: int * sourceWidth: int * sourceHeight: int * targetLeft: int * targetTop: int -> unit + 1 overload static member OpenStandardError: unit -> Stream + 1 overload static member OpenStandardInput: unit -> Stream + 1 overload static member OpenStandardOutput: unit -> Stream + 1 overload static member Read: unit -> int static member ReadKey: unit -> ConsoleKeyInfo + 1 overload static member ReadLine: unit -> string ...
<summary>Represents the standard input, output, and error streams for console applications. This class cannot be inherited.</summary>
Console.ReadLine() : string
val next: Free<CommandLineInstruction<unit>,unit>
Console.WriteLine() : unit
   (+0 other overloads)
Console.WriteLine(value: uint64) : unit
   (+0 other overloads)
Console.WriteLine(value: uint32) : unit
   (+0 other overloads)
Console.WriteLine(value: string) : unit
   (+0 other overloads)
Console.WriteLine(value: float32) : unit
   (+0 other overloads)
Console.WriteLine(value: obj) : unit
   (+0 other overloads)
Console.WriteLine(value: int64) : unit
   (+0 other overloads)
Console.WriteLine(value: int) : unit
   (+0 other overloads)
Console.WriteLine(value: float) : unit
   (+0 other overloads)
Console.WriteLine(value: decimal) : unit
   (+0 other overloads)
val readQuantity: Free<CommandLineInstruction<int>,int>
val monad<'monad<'t>> : MonadFxBuilder<'monad<'t>>
<summary> Creates a (lazy) monadic computation expression with side-effects (see http://fsprojects.github.io/FSharpPlus/computation-expressions.html for more information) </summary>
val l: string
val tryParse: value: string -> 'T option (requires member TryParse)
<summary> Converts to a value from its string representation. Returns None if the convertion doesn't succeed. </summary>
<category index="21">Converter</category>
union case Option.Some: Value: 'T -> Option<'T>
val dinerCount: int
union case Option.None: Option<'T>
val readDate: Free<CommandLineInstruction<DateTimeOffset>,DateTimeOffset>
Multiple items
[<Struct>] type DateTimeOffset = new: dateTime: DateTime -> unit + 8 overloads member Add: timeSpan: TimeSpan -> DateTimeOffset member AddDays: days: float -> DateTimeOffset member AddHours: hours: float -> DateTimeOffset member AddMicroseconds: microseconds: float -> DateTimeOffset member AddMilliseconds: milliseconds: float -> DateTimeOffset member AddMinutes: minutes: float -> DateTimeOffset member AddMonths: months: int -> DateTimeOffset member AddSeconds: seconds: float -> DateTimeOffset member AddTicks: ticks: int64 -> DateTimeOffset ...
<summary>Represents a point in time, typically expressed as a date and time of day, relative to Coordinated Universal Time (UTC).</summary>

--------------------
DateTimeOffset ()
DateTimeOffset(dateTime: DateTime) : DateTimeOffset
DateTimeOffset(dateTime: DateTime, offset: TimeSpan) : DateTimeOffset
DateTimeOffset(ticks: int64, offset: TimeSpan) : DateTimeOffset
DateTimeOffset(date: DateOnly, time: TimeOnly, offset: TimeSpan) : DateTimeOffset
DateTimeOffset(year: int, month: int, day: int, hour: int, minute: int, second: int, offset: TimeSpan) : DateTimeOffset
DateTimeOffset(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int, offset: TimeSpan) : DateTimeOffset
DateTimeOffset(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int, calendar: Globalization.Calendar, offset: TimeSpan) : DateTimeOffset
DateTimeOffset(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int, microsecond: int, offset: TimeSpan) : DateTimeOffset
DateTimeOffset(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int, microsecond: int, calendar: Globalization.Calendar, offset: TimeSpan) : DateTimeOffset
DateTimeOffset.TryParse(input: string, result: byref<DateTimeOffset>) : bool
DateTimeOffset.TryParse(input: ReadOnlySpan<char>, result: byref<DateTimeOffset>) : bool
DateTimeOffset.TryParse(s: string, provider: IFormatProvider, result: byref<DateTimeOffset>) : bool
DateTimeOffset.TryParse(s: ReadOnlySpan<char>, provider: IFormatProvider, result: byref<DateTimeOffset>) : bool
DateTimeOffset.TryParse(input: string, formatProvider: IFormatProvider, styles: Globalization.DateTimeStyles, result: byref<DateTimeOffset>) : bool
DateTimeOffset.TryParse(input: ReadOnlySpan<char>, formatProvider: IFormatProvider, styles: Globalization.DateTimeStyles, result: byref<DateTimeOffset>) : bool
val dt: DateTimeOffset
val readName: Free<CommandLineInstruction<string>,string>
val readEmail: Free<CommandLineInstruction<string>,string>
Reservation.Date: DateTimeOffset
Reservation.Name: string
Reservation.Email: string
Reservation.Quantity: int
Multiple items
val int: value: 'T -> int (requires member op_Explicit)

--------------------
type int = int32

--------------------
type int<'Measure> = int
val Quantity: int
val Date: DateTimeOffset
val Name: string
val Email: string
val readReservationRequest: Free<CommandLineInstruction<Reservation>,Reservation>
val curryN: f: ('T1 * ^T2 * ... * ^Tn -> 'Result) -> t: 'T1 -> 'T2 -> ... -> 'Tn -> 'Result (requires member Curry)
<summary> Takes a function expecting a tuple of any N number of elements and returns a function expecting N curried arguments. </summary>
<category index="0">Common Combinators</category>
type Reservation = { Date: DateTimeOffset Name: string Email: string Quantity: int } static member Create: Quantity: int * Date: DateTimeOffset * Name: string * Email: string -> Reservation
static member Reservation.Create: Quantity: int * Date: DateTimeOffset * Name: string * Email: string -> Reservation
val mainFunc: unit -> int
val sprintf: format: Printf.StringFormat<'T> -> 'T