Fork me on GitHub

Inline functions with member constraints Code Snippet

1
2
3
4
5
6
let inline fmap  f (x: ^t) =
(^t : (static member fmap : unit -> ((^a -> ^b) -> ^t -> ^c)) ()) f x
let inline liftA f (x: ^t) =
(^t : (static member liftA : unit -> (^a -> ^t -> ^b)) ()) f x
let inline liftM (x: ^t) f =
(^t : (static member liftM : unit -> (^t -> ^a -> ^b)) ()) x f

Inline functions with member constraints Code output:

> val inline fmap :
f:( ^a -> ^b) -> x: ^t -> ^c
when ^t : (static member fmap : -> ( ^a -> ^b) -> ^t -> ^c)
> val inline liftA :
f: ^a -> x: ^t -> ^b
when ^t : (static member liftA : -> ^a -> ^t -> ^b)
> val inline liftM :
x: ^t -> f: ^a -> ^b
when ^t : (static member liftM : -> ^t -> ^a -> ^b)

Inline operators with member constraints Code Snippet

1
2
3
let inline (<@>) f  m = fmap  f  m (* Sadly, <$> can't be used *)
let inline (<*>) fm m = liftA fm m
let inline (>>=) m f = liftM m f

Inline operators with member constraints Code output:

> val inline ( <@> ) :
f:( ^a -> ^b) -> m: ^c -> ^d
when ^c : (static member fmap : -> ( ^a -> ^b) -> ^c -> ^d)
> val inline ( <*> ) :
fm: ^a -> m: ^b -> ^c
when ^b : (static member liftA : -> ^a -> ^b -> ^c)
> val inline ( >>= ) :
m: ^a -> f: ^b -> ^c
when ^a : (static member liftM : -> ^a -> ^b -> ^c)

Maybe (Option) with fmap, liftA and liftM Code Snippet

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
type 'a Maybe = Just of 'a | Nothing

(* Functor *)
type 'a Maybe with
static member fmap () : ('a -> 'b) -> 'a Maybe -> 'b Maybe =
fun f -> function | Just x -> f x |> Just | Nothing -> Nothing

(* Applicative *)
type 'a Maybe with
static member liftA () : ('a -> 'b) Maybe -> 'a Maybe -> 'b Maybe =
fun fm ->
fun m ->
match fm,m with
| Just f, Just x -> f x |> Just
| ______________ -> Nothing

(* Monad *)
type 'a Maybe with
static member liftM () : 'a Maybe -> ('a -> 'b Maybe) -> 'b Maybe =
fun m ->
fun f ->
match m with
| Nothing -> Nothing
| Just x -> f x

(* Maybe with functions, the amount of parenthesis is to damn high *)
fmap ((+) 1) (Just 42);;
liftA (Just ((+) 1)) (Just 42);;
liftM (Just 42) (fun x -> x + 1 |> Just);;

(* Maybe with operators, fewer parenthesis *)
( (+) 1) <@> Just 42;;
Just ((+) 1) <*> Just 42;;
Just 42 >>= fun x -> x + 1 |> Just;;

Maybe (Option) with fmap, liftA and liftM Code output:

>
type 'a Maybe =
| Just of 'a
| Nothing
with
static member fmap : unit -> (('a -> 'b) -> 'a Maybe -> 'b Maybe)
static member liftA : unit -> (('a -> 'b) Maybe -> 'a Maybe -> 'b Maybe)
static member liftM : unit -> ('a Maybe -> ('a -> 'b Maybe) -> 'b Maybe)
end
> val it : int Maybe = Just 43
> val it : int Maybe = Just 43
> val it : int Maybe = Just 43
> val it : int Maybe = Just 43
> val it : int Maybe = Just 43
> val it : int Maybe = Just 43

Vect (list) with fmap, liftA and liftM Code Snippet

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
(* A list in F# is just a type abbreviation of a FSharpList *)
typedefof<List<_>> = typedefof<_ list>

(* Functor *)
type 'a List with
static member fmap () : ('a -> 'b) -> 'a list -> 'b list = List.map

(* This works *)
List.fmap () ((+) 1) [ 0 .. 10 ]

(* but this doesn't *)
// fmap ((+) 1) <@> [ 42 ]
(* error FS0001: The type ''a list' does not support the operator 'fmap' *)

(* Therefore, lets create our own type wrapping native lists in a Vector *)
type 'a Vect = Vect of 'a list

(* Functor *)
type 'a Vect with
static member fmap () : ('a -> 'b) -> 'a Vect -> 'b Vect =
fun f ->
fun (Vect xs) ->
List.map f xs |> Vect

(* Applicative *)
type 'a Vect with
static member liftA () : ('a -> 'b) Vect -> 'a Vect -> 'b Vect =
fun (Vect fs) ->
fun (Vect xs) ->
fs
|> List.map (fun f -> xs |> List.map f)
|> List.concat |> Vect

(* Monad *)
type 'a Vect with
static member liftM () : 'a Vect -> ('a list -> 'b Vect) -> 'b Vect =
fun (Vect xs) ->
fun f ->
f xs

(* Vect with operators, fewer parenthesis *)
( (+) 1) <@> Vect [ 0 .. 5 ];;
Vect [ id; ((+) 1) ] <*> Vect [ 0 .. 5 ];;
Vect [ 0 .. 5 ] >>= fun xs -> xs |> List.map ((+) 1) |> Vect;;

Vect (list) with fmap, liftA and liftM Code output:

> 
type List<'T> with
static member fmap : unit -> (('T -> 'b) -> 'T list -> 'b list)
type 'a Vect =
| Vect of 'a list
with
static member fmap : unit -> (('a -> 'b) -> 'a Vect -> 'b Vect)
static member liftA : unit -> (('a -> 'b) Vect -> 'a Vect -> 'b Vect)
static member liftM : unit -> ('a Vect -> ('a list -> 'b Vect) -> 'b Vect)
end
> val it : int Vect = Vect [1; 2; 3; 4; 5; 6]
> val it : int Vect = Vect [0; 1; 2; 3; 4; 5; 1; 2; 3; 4; 5; 6]
> val it : int Vect = Vect [1; 2; 3; 4; 5; 6]

Result (Choice) with fmap, liftA and liftM Code Snippet

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
type ('error,'a) Result = Ok of 'a | Err of 'error

(* Functor *)
type ('c,'a) Result with
static member fmap () : ('a -> 'b) -> ('c,'a) Result -> ('c,'b) Result =
fun f -> function | Ok x -> f x |> Ok | Err e -> Err e

(* Applicative *)
type ('c,'a) Result with
static member liftA () :
('c,('a -> 'b)) Result -> ('c,'a) Result -> ('c,'b) Result =
fun fm ->
fun m ->
match fm,m with
| Ok f, Ok x -> f x |> Ok
| Err e, _
| _ , Err e -> Err e

(* Monad *)
type ('c,'a) Result with
static member liftM () :
('c,'a) Result -> ('a -> ('c,'b) Result) -> ('c,'b) Result =
fun m ->
fun f ->
match m with
| Err e -> Err e
| Ok x -> f x

(* Result with operators, fewer parenthesis *)
( ((+) 1) <@> Ok 42 : (exn,int) Result);;
( Ok ((+) 1) <*> Ok 42 : (exn,int) Result);;
( Ok 42 >>= (fun x -> x + 1 |> Ok) : (exn,int) Result);;

Result (Choice) with fmap, liftA and liftM Code output:

>
type ('error,'a) Result =
| Ok of 'a
| Err of 'error
with
static member
fmap : unit -> (('a -> 'b) -> ('c,'a) Result -> ('c,'b) Result)
static member
liftA : unit ->
(('c,('a -> 'b)) Result -> ('c,'a) Result -> ('c,'b) Result)
static member
liftM : unit ->
(('c,'a) Result -> ('a -> ('c,'b) Result) -> ('c,'b) Result)
end
> val it : (exn,int) Result = Ok 43
> val it : (exn,int) Result = Ok 43
> val it : (exn,int) Result = Ok 43

Combining Maybe and Result using (»=) Code Snippet

1
2
3
4
5
6
7
8
9
10
11
let inc  x = x + 1
let incM x = inc x |> Just
let defM x = function | Just y -> y | Nothing -> x
let incR x = inc x |> Ok
let defR = function | Ok x -> x | Err e -> raise e

42
|> Just >>= incM >>= incM >>= incM >>= incM
|> defM 0
|> Ok >>= incR >>= incR >>= incR >>= incR
|> defR

Combining Maybe and Result using (»=) Code output:

> val inc : x:int -> int
> val incM : x:int -> int Maybe
> val defM : x:'a -> _arg1:'a Maybe -> 'a
> val incR : x:int -> ('a,int) Result
> val defR : _arg1:(#System.Exception,'b) Result -> 'b
> val it : int = 50

References:

comments powered by Disqus