# Understanding map

One important function in functional programming is the `map` function. When I learned F# I must admit that I had some problems first, understanding it. The problem was, I already knew the `map` function from dozens of other languages. Or to say it correctly, I mostly learned a wrong explanation of `map`.

The typical explanation I'm talking about often goes something like this: `map` takes a function and a `list`. It applies the function to every element in the list, and returns a new `list`. You will often see examples like this:

 ```1: 2: 3: 4: 5: 6: 7: 8: ``` ``````// F# let xs = List.map (fun x -> x * 2) [1;2;3;4;5] // C# var xs = Enumerable.Range(1,5).Select(x => x * 2) // Select is `map` // JavaScript var xs = [1,2,3,4,5].map(function(x) { return x * 2 }) ``````

All examples start with some kind of array collection that contains the numbers from 1 to 5. And all of them take a function multiplying the number by two. All of the examples will result in a new collection containing `[2;4;6;8;10]`.

While this explanation of `map` is right for `List.map`, this is not a right explanation of `map` in general. The problem starts when you encounter a functional language, because besides a `List.map` you will also encounter things like `String.map` or `Option.map`. On top you will also often find the advice that you should provide a `map` function for every type you create (if possible). When you have a `Result` type you should also provide a `Result.map`. Also a `Async.map` is a good idea. So if you only knew `map` from the idea of going through a collection you will probably suffer to understand what `map` is about. If you try to implement `map` for yourself, you will probably even wonder what `map` anyway should do for an arbitrary type? What is for example the purpose of `Async.map`?

To explain what `map` really is about, let's forget about what you already know and start from scratch again.

## Some functions

Before we look at `map`, let's create some simple functions. These functions will be used throughout the article.

 ```1: 2: 3: 4: 5: 6: 7: 8: ``` ``````// Squares a number: int -> int let square x = x * x // Add 10 to every number: int -> int let add10 x = x + 10 // Returns the length of a string: string -> int let length (str:string) = str.Length ``````

## List.map

We now assume that we don't have most of the functions from the `List` module. Especially not `List.map`. Sooner or later you will encounter one problem. With our `square` function we can square an `int`. But our `square` doesn't work at all with a `list<int>`.

So what do you do if you want to apply `square` to every `int` inside a `list`? You sure start looping over the list, and because we are immutable, we build a new list. As for easiness I write very imperative code with a loop, without recursion or `fold` or `foldBack`.

 ```1: 2: 3: 4: 5: 6: ``` ``````let squareList xs = let mutable results = [] for x in xs do let res = square x results <- res :: results List.rev results ``````

So what we now have is a `squareList` function, this function now takes a `list<int>` as input and returns a new `list<int>`. Our `squareList` function basically does the same thing as `square`, but instead of `int -> int` we have upgraded it somehow to work with `list<int> -> list<int>` instead.

A final note is the `List.rev` at the end, if it is unclear why we need it. `x :: xs` creates a new list, but it `prepends` elements. We actually cannot add elements to the end. So when we loop over a list like `[1;2;3;4;5]` we will first `square` 1 and add it to an empty list resulting in `[1]`. Then we `square` 2 and the result is added to `[1]` yielding in `[4;1]` and so on. That's why we have to reverse the list at the end when we are done!

Some time later we are faced with the problem that we also want to use our `add10` function on a `list` so we also write a new function for this.

 ```1: 2: 3: 4: 5: 6: ``` ``````let add10List xs = let mutable results = [] for x in xs do let res = add10 x results <- res :: results List.rev results ``````

Besides that the code is anyway not really nice or functional to begin with, the big problem is that we basically have written two completely identical functions! The only difference between those two functions is line 4. The only thing that is different is the function we call to compute `res`.

Because we like DRY (Don't Repeat Yourself) we do what functional programmers always tell Parametrize all the things. So instead of directly calling our function, we just expect that the concrete function to execute for every element is just passed as an argument. Or simply we Abstract those two functions. Abstracting always means that we put the things that are the same into one function, everything that is different will be expected as an argument. So what we finally end up with, is our own `map` function.

 ```1: 2: 3: 4: 5: 6: ``` ``````let mapList f xs = let mutable results = [] for x in xs do let mapping = f x results <- mapping :: results List.rev results ``````

We now can use `mapList` like this.

 ```1: 2: ``` ``````let listOfsquared = mapList square [1;2;3] // [1;4;9] let listOfAdd10 = mapList add10 [1;2;3] // [11;12;13] ``````

Currently it doesn't seems like a big difference to other introductions, but let's reconsider what lead to the idea of creating a `map` function. The idea was. We have a function `int -> int`. A `list<int>` contains `int` so we could use `square` or `add10` on every element. But in order to apply our function to every element we have to handle the `list`, and we need to loop through them. Because this process is the same for every function, we abstract the looping away in it's own function named `map`.

Before we go even deeper in why this is different from other explanation. Let's first look at the signature of our `mapList` function, and let's just remember the signature.

 ```1: ``` ``````('a -> 'b) -> list<'a> -> list<'b> ``````

## Option.map

Suddenly later when we are programming, we face a new problem. We encounter a `option<int>` value. `option<int>` contains an `int`. So because it contains an int, we also could use our `square` function on the inner value. But sure, now we have to handle `option`. So what do we do? We can sure unwrap it, and in case of a `Some` we apply our function to it. But what do we do in a case of `None`? Returning some kind of default int doesn't seem to make sense or like a good idea. So what we will instead do, we just create a new function that will return an `option` again. In the case of `None` we just return `None` and do nothing.

 ```1: 2: 3: 4: ``` ``````let squareOption opt = match opt with | None -> None | Some value -> Some (square value) ``````

Like `squareList` previously we now created a `squareOption`. It is already interesting to see some common between all those function. `square` could simply square an `int`. `squareList` could square a `list<int>` and now `squareOption` can square an `option<int>`. Let's go further and let's implement `add10Option`.

 ```1: 2: 3: 4: ``` ``````let add10Option opt = match opt with | None -> None | Some value -> Some (add10 value) ``````

Once again we can see the code duplication. So instead of checking again and again for every `option` if it is `None` or `Some` and only in the `Some` case call a function we starting to abstract it! Instead of calling our function directly, we once again expect it to be passed as an argument. We will call this abstract function `mapOption`.

 ```1: 2: 3: 4: ``` ``````let mapOption f opt = match opt with | None -> None | Some value -> Some (f value) ``````

We now can use `mapOption` like this.

 ```1: 2: 3: 4: ``` ``````let OptionSquare1 = mapOption square (Some 5) // Some 25 let OptionSquare2 = mapOption square None // None let OptionAdd10_1 = mapOption add10 (Some 5) // Some 15 let OptionAdd10_2 = mapOption add10 None // None ``````

Let's once again look at the type signature of our `mapOption`

 ```1: ``` ``````('a -> 'b) -> option -> option ``````

Does this already look familiar?

## The commonalities between `List.map` and `Option.map`

Now let's reconsider with what we started. We started with functions like `square` and `add10`. But those function only could work with `int`. But while we were programming we faced values like `list<int>` or `option<int>`. To use our functions on those values, we somehow have to unwrap the values. Apply our function to the inner type `int`, and wrap it up again. unwraping is different for every type. For `list` it means we loop through a list. For an `option` it means we have to check whether it is `Some` or `None`. But we still can think of it as some kind of an unwrap function. Because what we do is, at some point in our function we turn an `list<int>` or an `option<int>` just to in `int`, so we can use the `int` with our `square` or `add10` function. But after applying our function we still return the type of what we started. When we started with a `list<int>` we still have to return a `list` again. When we started with an `option` we still return an `option` again.

But this is a repetitive task, as this kind of unwraping and re-wraping is always the same. It doesn't matter which type we have inside `list<>` or `option`. And it also doesn't matter which function we use.

That's why we abstract those idea of unwrapping, applying a function, re-wrap into it's own function and name it `map`. To understand this process further let's look again at the type signatures of our `mapList` and `mapOption` function.

 ```1: 2: ``` ``````('a -> 'b) -> list<'a> -> list<'b> ('a -> 'b) -> option -> option ``````

This type-signature is the essence of a `map` function. Every `map` function has to look like this. The only part that changes is the wrapping-type. So at this point you could probably already assume how a `map` function for `Result`, `Async` or `Whatever` should look like

 ```1: 2: 3: ``` ``````('a -> 'b) -> Result<'a> -> Result<'b> ('a -> 'b) -> Async<'a> -> Async<'b> ('a -> 'b) -> Whatever<'a> -> Whatever<'b> ``````

## Currying and Partial Application

At this point it is important to talk about Currying. Currying is the idea that there only exists functions with one-argument and they always have to return a value. F# is such a language and does currying automatically.

That is also the very reason why you see multiple `->` inside a function signature. `->` is basically the symbol for a function. On it's left-side is the input of the function, on the right side is the output. When we look at a signature like

 ```1: ``` ``````string -> int -> float ``````

We often say it has two arguments, a `string` and a `int` and it returns a `float`. But this isn't quite correct. What we really have is a function that only has one argument a `string` and it will return a `int -> float`, or in other words. A new function! That is also the reason why functional languages don't use braces as arguments, it just uses a space. Something like

 ```1: ``` ``````let ys = List.map f xs ``````

really means. Execute `List.map f` this returns a new function, and we immediately pass `xs` to that new function. That's also the reason why we can add braces around the function and the first argument without changing the meaning.

 ```1: ``` ``````let ys = (List.map f) xs ``````

Not only that, we also can extract it, and save the intermediate function as a new value.

 ```1: 2: ``` ``````let newF = List.map f let ys = newF xs ``````

The idea to not pass all needed values is what we call Partial Application. The interesting stuff about all of this is, that with this idea, we can come up with different interpretation of the same function. And this kind of interpretation is what we can apply to `map`. Actually we can view `map` as a single argument function, or as a two argument functions. Both have some different meaning. When we interpret `map` as a single argument function, we now have something like this

Function

Input

Output

List.map

'a -> 'b

list<'a> -> list<'b>

Option.map

'a -> 'b

option<'a> -> option<'b>

Result.map

'a -> 'b

Result<'a> -> Result<'b>

Async.map

'a -> 'b

Async<'a> -> Async<'b>

Whatever.map

'a -> 'b

Whatever<'a> -> Whatever<'b>

It basically means we can think of `map` of some kind of function that can upgrade a function. If we pass a `int -> string` function for example to `List.map` we get a `list<int> -> list<string>` function back! If we pass the same function to `Async.map` we get a `Async<int> -> Async<string>` function back.

So `map` is a way to upgrade both sides (input and output) and add a layer to both sides. There are two reason on why this concept is important.

1. Code-Reuse. If a type supports `map`, you just can upgrade a function to work with this type.
2. In your own functions, you don't need to care about the layer itself.

## Code Reuse

So let's look again at our starting functions and just use them with the already built-in `List.map` and `Option.map` functions.

 ```1: 2: 3: 4: 5: 6: 7: ``` ``````let squareL = List.map square let add10L = List.map add10 let lengthL = List.map length let squareO = Option.map square let add10O = Option.map add10 let lengthO = Option.map length ``````

So we just can reuse our three functions. We never have to write special functions that loops through a list. Or that handles `option`, `Async`, `Result`, we just can upgrade any function we already have written.

## You don't need to care for the layers

This is probably the biggest advantage, as you don't have to care for the layers. You want to convert a list of `int` to a list of `string`. Just write a function that does `int -> string` no List handling, no looping, no recursion. Use `List.map` and you are done.

And the big advantage. You also can use that function with `Option.map` to turn it into a function that works on a `option` type. If you pass it to `Async.map` you get a function that can work on an asynchronous value. You don't need to write code for looping through a list, do pattern match an option, or write code to handle asynchronicity.

All of this is done for you by the `map` function!

## Async.map

Currently F# don't have a built-in `Async.map` function. So let's create the `map` function for `Async` ourselves.

 ```1: 2: 3: 4: 5: 6: ``` ``````module Async = let map f op = async { let! x = op let value = f x return value } ``````

So how do we now that we have to implement it in this way? Because that is what the type-signature is telling us. We have to write a function with the signature

 ```1: ``` ``````('a -> 'b) -> Async<'a> -> Async<'b> ``````
1. That means a function with two arguments. The first arguments is a function `'a -> 'b`, the second is an `Async<'a>`, and we have to return an `Async<'b>`.
2. Because we have to return an `Async` we start with `async { ... }`.
3. Now `op` is an `Async<'a>`, with `let! x = op` we run the the async operation. This will unwrap our `Async<'a>` and just returns an `'a`.
4. We can pass that `'a` to our function `f` that converts `'a` to an `'b`.
5. Once we have a `'b` we `return` it. `return` basically wraps the `'b` and adds the `Async<>` layer.

## Stacking Layers

The interesting idea is now. We are not restricted to adding a single layer. We can add as much layer we want and stack them. For example we could have `option` values that are wrapped inside a `list` returned by an `Async` operation.

To be more concrete. Let's assume we have some kind of async operation that downloads from a website (The Async layer). This tries to Parse a table on a website that contains numbers (The List Layer). But because parsing could fail, for example a table entry is not a number, we wrap it in a `Option` (The Optional Layer).

Let's write a mock function that returns this kind of data.

 ```1: 2: 3: 4: 5: 6: 7: 8: ``` ``````let downloadPage = async { // Simulating Download, wait 1 second do! Async.Sleep 1000 // A list of optionals list> let numbers = [Some 1; Some 2; None; Some 3; None; None; Some 10] // return it: This adds async<> layer return numbers } ``````

What we now have is a `Async<list<option<int>>>`. Puh looks complicated! So what do we now if we want to square the `int` inside our `Async<List<Option<...>>>` construct? We just add one layer after another to `square`. At first, we do a `Option.map` on `square`. The result of this is a function that we pass to `List.map` that adds the `List` layer. And once again the `Async.map` finally adds the `Async` layer.

 ```1: ``` ``````let squaring = Async.map (List.map (Option.map square)) ``````

We now have `squaring` that has the following signature

 ```1: ``` ``````Async>> -> Async>> ``````

We can now do

 ```1: ``` ``````let data = Async.RunSynchronously (squaring downloadPage) ``````

And `data` will be `[Some 1; Some 4; None; Some 9; None; None; Some 100]`

All `Option`, `List` and `Async` handling was handled for us. We just upgraded `square` with the different `map` functions until it matches our needed signature.

Let's assume we wouldn't have `Async.map`, `List.map`, `Option.map`. We would have needed to write it like this.

 ``` 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: ``` ``````let squaring' input = async { let! data = input let squared = [ for x in data -> match x with | None -> None | Some value -> Some (square value) ] return squared } ``````

## Functors

Whenever we have a type with a `map` function we call it a Functor if the implementation of `map` satisfies two laws. Those two laws ensures that `map` is predictable and don't do additional stuff we didn't expect.

### 1. Law: Mapping `id`

The first rule says that mapping over the `id` function must not change the input. The `id` function is just a function that returns its input as-is

 ```1: ``` ``````let id x = x ``````

So when we write

 ```1: ``` ``````let xs = List.map id [1;2;3;4;5] ``````

Then `xs` still must be `[1;2;3;4;5]`.

### 2. Law: Function composition

The second rule says that composing two functions and then mapping, should be the same as mapping over both functions separately.

 ``` 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: ``` ``````// 1 solution: compose two functions, and then map let comp = square >> add10 let cxs = List.map comp [1;2;3;4;5] // 2 solution: mapping it two times let sxs = [1;2;3;4;5] |> List.map square |> List.map add10 cxs = sxs // must be the same ``````

It shouldn't matter if we go through the list take one element and then do `square` and `add10` in one-step. Or if we go trough our list two times and do it in two separately steps. Both `cxs` and `sxs` have to return the same result `[11;14;19;26;35]`

Because `List.map` satisfies both laws, we say that `List` is a functor.

## Summary

I hope it is now clear why `map` is such an important function. Implementing a `map` function just means you can upgrade already available functions. It opens up a lot of code reuse as you don't have to write special glue code that handles your type/layer.

It also can make writing new functions easier, as you don't have to care about a layer. If you find yourself writing a function that has a list as its input and a list as its output then you are probably doing something wrong! The same goes for every other type.

Not only is it easier to just write a function that don't contain any list/looping/recursion logic. Such a function is even more reusable.

## Further Reading

module Main
val xs : int list

Full name: understandingmap.xs
Multiple items
module List

from Microsoft.FSharp.Collections

--------------------
type List<'T> =
| ( [] )
| ( :: ) of Head: 'T * Tail: 'T list
interface IEnumerable
interface IEnumerable<'T>
member GetSlice : startIndex:int option * endIndex:int option -> 'T list
member Head : 'T
member IsEmpty : bool
member Item : index:int -> 'T with get
member Length : int
member Tail : 'T list
static member Cons : head:'T * tail:'T list -> 'T list
static member Empty : 'T list

Full name: Microsoft.FSharp.Collections.List<_>
val map : mapping:('T -> 'U) -> list:'T list -> 'U list

Full name: Microsoft.FSharp.Collections.List.map
val x : int
val square : x:int -> int

Full name: Main.square
val add10 : x:int -> int

Full name: Main.add10
val length : str:string -> int

Full name: Main.length
val str : string
Multiple items
val string : value:'T -> string

Full name: Microsoft.FSharp.Core.Operators.string

--------------------
type string = System.String

Full name: Microsoft.FSharp.Core.string
property System.String.Length: int
val squareList : xs:seq<int> -> int list

Full name: Main.squareList
val xs : seq<int>
val mutable results : int list
val res : int
val rev : list:'T list -> 'T list

Full name: Microsoft.FSharp.Collections.List.rev
val add10List : xs:seq<int> -> int list

Full name: Main.add10List
val mapList : f:('a -> 'b) -> xs:seq<'a> -> 'b list

Full name: Main.mapList
val f : ('a -> 'b)
val xs : seq<'a>
val mutable results : 'b list
val x : 'a
val mapping : 'b
val listOfsquared : int list

Full name: Main.listOfsquared
val listOfAdd10 : int list

Full name: Main.listOfAdd10
type 'T list = List<'T>

Full name: Microsoft.FSharp.Collections.list<_>
val squareOption : opt:int option -> int option

Full name: Main.squareOption
val opt : int option
union case Option.None: Option<'T>
union case Option.Some: Value: 'T -> Option<'T>
val value : int
val add10Option : opt:int option -> int option

Full name: Main.add10Option
val mapOption : f:('a -> 'b) -> opt:'a option -> 'b option

Full name: Main.mapOption
val opt : 'a option
val value : 'a
val OptionSquare1 : int option

Full name: Main.OptionSquare1
val OptionSquare2 : int option

Full name: Main.OptionSquare2
val OptionAdd10_1 : int option

Full name: Main.OptionAdd10_1
val OptionAdd10_2 : int option

Full name: Main.OptionAdd10_2
type 'T option = Option<'T>

Full name: Microsoft.FSharp.Core.option<_>
Multiple items
val int : value:'T -> int (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.int

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

Full name: Microsoft.FSharp.Core.int

--------------------
type int<'Measure> = int

Full name: Microsoft.FSharp.Core.int<_>
Multiple items
type Async
static member AsBeginEnd : computation:('Arg -> Async<'T>) -> ('Arg * AsyncCallback * obj -> IAsyncResult) * (IAsyncResult -> 'T) * (IAsyncResult -> unit)
static member AwaitEvent : event:IEvent<'Del,'T> * ?cancelAction:(unit -> unit) -> Async<'T> (requires delegate and 'Del :> Delegate)
static member AwaitIAsyncResult : iar:IAsyncResult * ?millisecondsTimeout:int -> Async<bool>
static member AwaitTask : task:Task -> Async<unit>
static member AwaitTask : task:Task<'T> -> Async<'T>
static member AwaitWaitHandle : waitHandle:WaitHandle * ?millisecondsTimeout:int -> Async<bool>
static member CancelDefaultToken : unit -> unit
static member Catch : computation:Async<'T> -> Async<Choice<'T,exn>>
static member FromBeginEnd : beginAction:(AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromBeginEnd : arg:'Arg1 * beginAction:('Arg1 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromBeginEnd : arg1:'Arg1 * arg2:'Arg2 * beginAction:('Arg1 * 'Arg2 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromBeginEnd : arg1:'Arg1 * arg2:'Arg2 * arg3:'Arg3 * beginAction:('Arg1 * 'Arg2 * 'Arg3 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromContinuations : callback:(('T -> unit) * (exn -> unit) * (OperationCanceledException -> unit) -> unit) -> Async<'T>
static member Ignore : computation:Async<'T> -> Async<unit>
static member OnCancel : interruption:(unit -> unit) -> Async<IDisposable>
static member Parallel : computations:seq<Async<'T>> -> Async<'T []>
static member RunSynchronously : computation:Async<'T> * ?timeout:int * ?cancellationToken:CancellationToken -> 'T
static member Sleep : millisecondsDueTime:int -> Async<unit>
static member Start : computation:Async<unit> * ?cancellationToken:CancellationToken -> unit
static member StartAsTask : computation:Async<'T> * ?taskCreationOptions:TaskCreationOptions * ?cancellationToken:CancellationToken -> Task<'T>
static member StartChild : computation:Async<'T> * ?millisecondsTimeout:int -> Async<Async<'T>>
static member StartChildAsTask : computation:Async<'T> * ?taskCreationOptions:TaskCreationOptions -> Async<Task<'T>>
static member StartImmediate : computation:Async<unit> * ?cancellationToken:CancellationToken -> unit
static member StartWithContinuations : computation:Async<'T> * continuation:('T -> unit) * exceptionContinuation:(exn -> unit) * cancellationContinuation:(OperationCanceledException -> unit) * ?cancellationToken:CancellationToken -> unit
static member SwitchToContext : syncContext:SynchronizationContext -> Async<unit>
static member SwitchToNewThread : unit -> Async<unit>
static member SwitchToThreadPool : unit -> Async<unit>
static member TryCancelled : computation:Async<'T> * compensation:(OperationCanceledException -> unit) -> Async<'T>
static member CancellationToken : Async<CancellationToken>
static member DefaultCancellationToken : CancellationToken

Full name: Microsoft.FSharp.Control.Async

--------------------
type Async<'T>

Full name: Microsoft.FSharp.Control.Async<_>
Multiple items
val float : value:'T -> float (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.float

--------------------
type float = System.Double

Full name: Microsoft.FSharp.Core.float

--------------------
type float<'Measure> = float

Full name: Microsoft.FSharp.Core.float<_>
val squareL : (int list -> int list)

Full name: Main.squareL
val add10L : (int list -> int list)

Full name: Main.add10L
val lengthL : (string list -> int list)

Full name: Main.lengthL
val squareO : (int option -> int option)

Full name: Main.squareO
module Option

from Microsoft.FSharp.Core
val map : mapping:('T -> 'U) -> option:'T option -> 'U option

Full name: Microsoft.FSharp.Core.Option.map
val add10O : (int option -> int option)

Full name: Main.add10O
val lengthO : (string option -> int option)

Full name: Main.lengthO
val map : f:('a -> 'b) -> op:Async<'a> -> Async<'b>

Full name: Main.Async.map
val op : Async<'a>
val async : AsyncBuilder

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.async
val value : 'b
val downloadPage : Async<int option list>

Full name: Main.downloadPage
Multiple items
module Async

from Main

--------------------
type Async
static member AsBeginEnd : computation:('Arg -> Async<'T>) -> ('Arg * AsyncCallback * obj -> IAsyncResult) * (IAsyncResult -> 'T) * (IAsyncResult -> unit)
static member AwaitEvent : event:IEvent<'Del,'T> * ?cancelAction:(unit -> unit) -> Async<'T> (requires delegate and 'Del :> Delegate)
static member AwaitIAsyncResult : iar:IAsyncResult * ?millisecondsTimeout:int -> Async<bool>
static member AwaitTask : task:Task -> Async<unit>
static member AwaitTask : task:Task<'T> -> Async<'T>
static member AwaitWaitHandle : waitHandle:WaitHandle * ?millisecondsTimeout:int -> Async<bool>
static member CancelDefaultToken : unit -> unit
static member Catch : computation:Async<'T> -> Async<Choice<'T,exn>>
static member FromBeginEnd : beginAction:(AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromBeginEnd : arg:'Arg1 * beginAction:('Arg1 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromBeginEnd : arg1:'Arg1 * arg2:'Arg2 * beginAction:('Arg1 * 'Arg2 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromBeginEnd : arg1:'Arg1 * arg2:'Arg2 * arg3:'Arg3 * beginAction:('Arg1 * 'Arg2 * 'Arg3 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromContinuations : callback:(('T -> unit) * (exn -> unit) * (OperationCanceledException -> unit) -> unit) -> Async<'T>
static member Ignore : computation:Async<'T> -> Async<unit>
static member OnCancel : interruption:(unit -> unit) -> Async<IDisposable>
static member Parallel : computations:seq<Async<'T>> -> Async<'T []>
static member RunSynchronously : computation:Async<'T> * ?timeout:int * ?cancellationToken:CancellationToken -> 'T
static member Sleep : millisecondsDueTime:int -> Async<unit>
static member Start : computation:Async<unit> * ?cancellationToken:CancellationToken -> unit
static member StartAsTask : computation:Async<'T> * ?taskCreationOptions:TaskCreationOptions * ?cancellationToken:CancellationToken -> Task<'T>
static member StartChild : computation:Async<'T> * ?millisecondsTimeout:int -> Async<Async<'T>>
static member StartChildAsTask : computation:Async<'T> * ?taskCreationOptions:TaskCreationOptions -> Async<Task<'T>>
static member StartImmediate : computation:Async<unit> * ?cancellationToken:CancellationToken -> unit
static member StartWithContinuations : computation:Async<'T> * continuation:('T -> unit) * exceptionContinuation:(exn -> unit) * cancellationContinuation:(OperationCanceledException -> unit) * ?cancellationToken:CancellationToken -> unit
static member SwitchToContext : syncContext:SynchronizationContext -> Async<unit>
static member SwitchToNewThread : unit -> Async<unit>
static member SwitchToThreadPool : unit -> Async<unit>
static member TryCancelled : computation:Async<'T> * compensation:(OperationCanceledException -> unit) -> Async<'T>
static member CancellationToken : Async<CancellationToken>
static member DefaultCancellationToken : CancellationToken

Full name: Microsoft.FSharp.Control.Async

--------------------
type Async<'T>

Full name: Microsoft.FSharp.Control.Async<_>
static member Async.Sleep : millisecondsDueTime:int -> Async<unit>
val numbers : int option list
val squaring : (Async<int option list> -> Async<int option list>)

Full name: Main.squaring
val data : int option list

Full name: Main.data
static member Async.RunSynchronously : computation:Async<'T> * ?timeout:int * ?cancellationToken:System.Threading.CancellationToken -> 'T
val squaring' : input:Async<#seq<int option>> -> Async<int option list>

Full name: Main.squaring'
val input : Async<#seq<int option>>
val data : #seq<int option>
val squared : int option list
val x : int option
val id : x:'T -> 'T

Full name: Microsoft.FSharp.Core.Operators.id
val xs : int list

Full name: Main.xs
val comp : (int -> int)

Full name: Main.comp
val cxs : int list

Full name: Main.cxs
val sxs : int list

Full name: Main.sxs