FSharpPlus


Applicative

A functor with application, providing operations to embed pure expressions (return), and sequence computations and combine their results (<*>). ___

Minimal complete definition

static member Return (x: 'T) : 'Applicative<'T>
static member (<*>) (f: 'Applicative<'T -> 'U>, x: 'Applicative<'T>) : 'Applicative<'U>

Note: return can't be used outside computation expressions, use result instead.

Other operations

static member Lift2 (f: 'T1 -> 'T2 -> 'T, x1: 'Applicative<'T1>, x2: 'Applicative<'T2>) : 'Applicative<'T>

Rules

result id <*> v = v
result (<<) <*> u <*> v <*> w = u <*> (v <*> w)
result f <*> result x = result (f x)
u <*> result y = result ((|>) y) <*> u

Related Abstractions

From F#+

Restricted: - string - StringBuilder - Set<'T> - IEnumerator<'T>

Only for <*> operation: - Map<'Key, 'T> - Dictionary<'Key, 'T> - IDictionary<'Key, 'T> - IReadOnlyDictionary<'Key, 'T>

Suggest another concrete implementation

Examples

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

// Apply +4 to a list
let lst5n6  = map ((+) 4) [ 1; 2 ]

// Apply +4 to an array
let arr5n6  = map ((+) 4) [|1; 2|]

// I could have written this
let arr5n6' = (+) <!> [|4|] <*> [|1; 2|]

// Add two options
let opt120  = (+) <!> Some 20 <*> tryParse "100"


// Applicatives need Return (result)

// Test return
let resSome22 : option<_> = result 22
let resSing22 : list<_>   = result 22
let resLazy22 : Lazy<_>   = result 22
let (quot5 : Microsoft.FSharp.Quotations.Expr<int>) = result 5

// Example
type Person = { Name: string; Age: int } with static member create n a = { Name = n; Age = a }

let person1 = Person.create <!> tryHead ["gus"] <*> tryParse "42"
let person2 = Person.create <!> tryHead ["gus"] <*> tryParse "fourty two"
let person3 = Person.create <!> tryHead ["gus"] <*> (tryHead ["42"] >>= tryParse)


// Other ways to write applicative expressions


// Function lift2 helps in many cases

let person1' = (tryHead ["gus"], tryParse "42")               ||> lift2 Person.create 
let person2' = (tryHead ["gus"], tryParse "fourty two")       ||> lift2 Person.create 
let person3' = (tryHead ["gus"], tryHead ["42"] >>= tryParse) ||> lift2 Person.create 


// Using Idiom brackets from http://www.haskell.org/haskellwiki/Idiom_brackets

let res3n4   = iI ((+) 2) [1;2] Ii
let res3n4'  = iI (+) (result 2) [1;2] Ii
let res18n24 = iI (+) (ZipList(seq [8;4])) (ZipList(seq [10;20])) Ii

let tryDiv x y = if y = 0 then None else Some (x </div/> y)
let resSome3   = join (iI tryDiv (Some 6) (Some 2) Ii)
let resSome3'  =       iI tryDiv (Some 6) (Some 2) Ji

let tryDivBy y = if y = 0 then None else Some (fun x -> x </div/> y)
let resSome2  = join (result tryDivBy  <*> Some 4) <*> Some 8
let resSome2' = join (   iI tryDivBy (Some 4) Ii) <*> Some 8

let resSome2'' = iI tryDivBy (Some 4) J (Some 8) Ii
let resNone    = iI tryDivBy (Some 0) J (Some 8) Ii
let res16n17   = iI (+) (iI (+) (result 4) [2; 3] Ii) [10] Ii

let opt121  = iI (+) (Some 21) (tryParse "100") Ii
let opt122  = iI tryDiv (tryParse "488") (trySqrt 16) Ji


// Using applicative math operators

open FSharpPlus.Math.Applicative

let opt121'  = Some 21 .+. tryParse "100"
let optTrue  = 30 >. tryParse "29"
let optFalse = tryParse "30" .< 29
let m1m2m3 = -.[1; 2; 3]


// Using applicative computation expression

let getName s = tryHead s
let getAge  s = tryParse s

let person4 = applicative {
    let! name = getName ["gus"]
    and! age  = getAge "42"
    return { Name = name; Age = age } }

Composing applicatives

Unlike monads, applicatives are always composable.

The date type Compose<'Applicative1<'Applicative2<'T>>> can be used to compose any 2 applicatives:

let res4 = (+) <!> Compose [Some 3] <*> Compose [Some 1]

let getNameAsync s = async { return tryHead s }
let getAgeAsync  s = async { return tryParse s }

let person5 = Person.create <!> Compose (getNameAsync ["gus"]) <*> Compose (getAgeAsync "42")

The computation expressions applicative2 and applicative3 can also be used to compose applicatives:

let person6 = applicative2 {
    let! name = printfn "aa"; getNameAsync ["gus"]
    and! age  = getAgeAsync "42"
    return { Name = name; Age = age } }




// A Monad is automatically an Applicative

type MyList<'s> = MyList of 's seq with
    static member Return (x: 'a) = MyList (Seq.singleton x)
    static member (>>=)  (MyList x: MyList<'T>, f) = MyList (Seq.collect (f >> (fun (MyList x) -> x)) x)

let mappedMyList : MyList<_> = (MyList [(+) 1; (+) 2; (+) 3]) <*> (MyList [1; 2; 3])

Recommended reading

val id: x: 'T -> 'T
namespace FSharpPlus
namespace FSharpPlus.Data
val lst5n6: int list
val map: f: ('T -> 'U) -> x: 'Functor<'T> -> 'Functor<'U> (requires member Map)
<summary>Lifts a function into a Functor.</summary>
<category index="1">Functor</category>
val arr5n6: int array
val arr5n6': int array
val opt120: int option
union case Option.Some: Value: 'T -> Option<'T>
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>
val resSome22: int option
Multiple items
val option: f: ('g -> 'h) -> n: 'h -> _arg1: 'g option -> 'h
<summary> Takes a function, a default value and a option value. If the option value is None, the function returns the default value. Otherwise, it applies the function to the value inside Some and returns the result. </summary>
<category index="0">Common Combinators</category>


--------------------
type 'T option = Option<'T>
val result: x: 'T -> 'Functor<'T> (requires member Return)
<summary> Lifts a value into a Functor. Same as return in Computation Expressions. </summary>
<category index="2">Applicative</category>
val resSing22: int list
type 'T list = List<'T>
val resLazy22: Lazy<int>
Multiple items
active recognizer Lazy: Lazy<'T> -> 'T

--------------------
module Lazy from FSharpPlus
<summary> Additional operations on Lazy - delayed computations </summary>

--------------------
type Lazy<'T> = System.Lazy<'T>
val quot5: Quotations.Expr<int>
namespace Microsoft
namespace Microsoft.FSharp
namespace Microsoft.FSharp.Quotations
Multiple items
type Expr = override Equals: obj: obj -> bool member GetFreeVars: unit -> Var seq member Substitute: substitution: (Var -> Expr option) -> Expr member ToString: full: bool -> string static member AddressOf: target: Expr -> Expr static member AddressSet: target: Expr * value: Expr -> Expr static member Application: functionExpr: Expr * argument: Expr -> Expr static member Applications: functionExpr: Expr * arguments: Expr list list -> Expr static member Call: methodInfo: MethodInfo * arguments: Expr list -> Expr + 1 overload static member CallWithWitnesses: methodInfo: MethodInfo * methodInfoWithWitnesses: MethodInfo * witnesses: Expr list * arguments: Expr list -> Expr + 1 overload ...

--------------------
type Expr<'T> = inherit Expr member Raw: Expr
Multiple items
val int: value: 'T -> int (requires member op_Explicit)

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

--------------------
type int<'Measure> = int
Person.Name: string
Multiple items
val string: value: 'T -> string

--------------------
type string = System.String
Person.Age: int
val n: string
val a: int
val person1: Person option
type Person = { Name: string Age: int } static member create: n: string -> a: int -> Person
static member Person.create: n: string -> a: int -> Person
val tryHead: source: 'Foldable<'T> -> 'T option (requires member TryHead)
<summary>Gets the first element of the foldable, or <c>None</c> if the foldable is empty.</summary>
<category index="11">Foldable</category>
<param name="source">The input foldable.</param>
<returns>The first element of the foldable or None.</returns>
val person2: Person option
val person3: Person option
val person1': Person option
val lift2: f: ('T -> 'U -> 'V) -> x: 'Applicative<'T> -> y: 'Applicative<'U> -> 'Applicative<'V> (requires member Lift2)
<summary> Applies 2 lifted arguments to a non-lifted function. Equivalent to map2 in non list-like types. </summary>
<category index="2">Applicative</category>
val person2': Person option
val person3': Person option
val res3n4: int list
val iI: x: 'a -> ('b -> 'd) (requires member ($) and member Return)
Multiple items
union case Ii.Ii: Ii

--------------------
type Ii = | Ii
val res3n4': int list
val res18n24: ZipList<int>
Multiple items
union case ZipList.ZipList: 's seq -> ZipList<'s>

--------------------
module ZipList from FSharpPlus.Data
<summary> Basic operations on ZipList </summary>

--------------------
type ZipList<'s> = | ZipList of 's seq member Item: n: int -> 's static member (+) : x: ZipList<'a> * y: ZipList<'a> -> ZipList<'a> (requires member ``+``) static member (<*>) : ZipList<('a -> 'b)> * ZipList<'a> -> ZipList<'b> static member (<|>) : ZipList<'a1> * ZipList<'a1> -> ZipList<'a1> static member Return: x: 'a -> ZipList<'a> static member ToSeq: ZipList<'a1> -> 'a1 seq static member Traverse: ZipList<'T> * f: ('T -> 'Functor<'U>) -> 'Functor<ZipList<'U>> (requires member Map and member ``<*>`` and member IsLeftZero and member Map and member Map and member Traverse and member Return and member Map) static member get_Empty: unit -> ZipList<'a1> static member Zero: unit -> ZipList<'a> (requires member Zero)
<summary> A sequence with an Applicative functor based on zipping. </summary>
Multiple items
val seq: sequence: 'T seq -> 'T seq

--------------------
type 'T seq = System.Collections.Generic.IEnumerable<'T>
val tryDiv: x: int -> y: int -> int option
val x: int
val y: int
union case Option.None: Option<'T>
val div: dividend: 'Num -> divisor: 'Num -> 'Num (requires member Divide)
<summary>Division between two numbers. If the numbers are not divisible throws an error.</summary>
<category index="22">Numerics</category>
val resSome3: int option
val join: x: 'Monad<Monad<'T>> -> 'Monad<'T> (requires member Join)
<summary> Flattens two layers of monadic information into one. </summary>
<category index="3">Monad</category>
val resSome3': int option
Multiple items
union case Ji.Ji: Ji

--------------------
type Ji = | Ji
val tryDivBy: y: int -> (int -> int) option
val resSome2: int option
val resSome2': int option
val resSome2'': int option
union case J.J: J
val resNone: int option
val res16n17: int list
val opt121: int option
val opt122: int option
val trySqrt: x: 'a -> 'a option (requires member TrySqrt)
<summary>Square root of a number of any type. Returns None if there is no square root.</summary>
<category index="22">Numerics</category>
namespace FSharpPlus.Math
module Applicative from FSharpPlus.Math
<summary>Math Operators ready to use over Applicative Functors.</summary>
val opt121': int option
val optTrue: bool option
val optFalse: bool option
val m1m2m3: int list
val getName: s: string list -> string option
val s: string list
val getAge: s: string -> int option
val s: string
val person4: Person option
val applicative<'Applicative<'T>> : ApplicativeBuilder<'Applicative<'T>>
<summary> Creates a (sequential) applicative computation expression. </summary>
val name: string
val age: int
val res4: Compose<int option list>
Multiple items
union case Compose.Compose: 'functorF<'functorG<'t>> -> Compose<'functorF<'functorG<'t>>>

--------------------
module Compose from FSharpPlus.Data
<summary> Basic operations on Compose </summary>

--------------------
[<Struct>] type Compose<'functorF<'functorG<'t>>> = | Compose of 'functorF<'functorG<'t>> static member ( *> ) : x: 'FunctorF<'FunctorG<'T>> * y: 'FunctorF<'FunctorG<'U>> -> 'FunctorF<'FunctorG<'U>> (requires member Map and member ``<*>``) static member (<!>) : f: ('T -> 'U) * x: 'FunctorF<'FunctorG<'T>> -> Compose<'FunctorF<'FunctorG<'U>>> (requires member Map and member Map) static member ( <* ) : x: 'FunctorF<'FunctorG<'U>> * y: 'FunctorF<'FunctorG<'T>> -> 'FunctorF<'FunctorG<'U>> (requires member ``<*>`` and member Map) static member (<*>) : Compose<'ApplicativeF<'ApplicativeG<'T -> 'U>> * Compose<'ApplicativeF<'ApplicativeG<'T>> -> Compose<'ApplicativeF<'ApplicativeG<'U>> (requires member Map and member ``<*>`` and member ``<*>``) static member (<.>) : Compose<'ApplicativeF<'ApplicativeG<'T -> 'U>> * Compose<'ApplicativeF<'ApplicativeG<'T>> -> Compose<'ApplicativeF<'ApplicativeG<'U>> (requires member Map and member ``<.>`` and member ``<.>``) static member (<|>) : Compose<'AlternativeF<'ApplicativeG<'T>> * Compose<'AlternativeF<'ApplicativeG<'T>> -> Compose<'AlternativeF<'ApplicativeG<'T>> (requires member ``<|>``) static member Lift2: f: ('T -> 'U -> 'V) * Compose<'ApplicativeF<'ApplicativeG<'T>> * Compose<'ApplicativeF<'ApplicativeG<'U>> -> Compose<'ApplicativeF<'ApplicativeG<'V>> (requires member Lift2 and member Lift2) static member Lift3: f: ('T -> 'U -> 'V -> 'W) * Compose<'ApplicativeF<'ApplicativeG<'T>> * Compose<'ApplicativeF<'ApplicativeG<'U>> * Compose<'ApplicativeF<'ApplicativeG<'V>> -> Compose<'ApplicativeF<'ApplicativeG<'W>> (requires member Lift3 and member Lift3) static member Map: Compose<'FunctorF<'FunctorG<'T>>> * f: ('T -> 'U) -> Compose<'FunctorF<'FunctorG<'U>>> (requires member Map and member Map) static member Map2: f: ('T -> 'U -> 'V) * Compose<'ApplicativeF<'ApplicativeG<'T>> * Compose<'ApplicativeF<'ApplicativeG<'U>> -> Compose<'ApplicativeF<'ApplicativeG<'V>> (requires member Map2 and member Map2) ...
<summary> Right-to-left composition of functors. The composition of applicative functors is always applicative, but the composition of monads is not always a monad. </summary>
val getNameAsync: s: string list -> Async<string option>
val async: AsyncBuilder
val getAgeAsync: s: string -> Async<int option>
val person5: Compose<Async<Person option>>
val person6: Async<Person option>
val applicative2<'Applicative1<Applicative2<'T>>> : ApplicativeBuilder2<'Applicative1<Applicative2<'T>>>
<summary> Creates a (sequential) applicative computation expression which compose effects of two Applicatives. </summary>
val printfn: format: Printf.TextWriterFormat<'T> -> 'T
's
Multiple items
union case MyList.MyList: 's seq -> MyList<'s>

--------------------
type MyList<'s> = | MyList of 's seq static member (>>=) : MyList<'T> * f: ('T -> MyList<'a>) -> MyList<'a> static member Return: x: 'a -> MyList<'a>
val x: 'a
'a
Multiple items
module Seq from FSharpPlus.Data
<summary> Additional operations on Seq </summary>

--------------------
module Seq from FSharpPlus.Operators

--------------------
module Seq from FSharpPlus
<summary> Additional operations on Seq </summary>

--------------------
module Seq from Microsoft.FSharp.Collections
val singleton: value: 'T -> 'T seq
val x: 'T seq
'T
val f: ('T -> MyList<'a>)
val collect: mapping: ('T -> #('U seq)) -> source: 'T seq -> 'U seq
val x: 'a seq
val mappedMyList: MyList<int>