├── FSTan
├── Show.fs
├── MonadTrans.fs
├── Functor.fs
├── FSTan.fsproj
├── Data
│ ├── Identity.fs
│ ├── List.fs
│ ├── Either.fs
│ └── Maybe.fs
├── Monad.fs
├── Monoid.fs
├── HKT.fs
├── Applicative.fs
└── Control
│ ├── Trans
│ └── State.fs
│ └── State.fs
├── Tutorials
├── Tutorials.fsproj
└── Program.fs
├── FSTan.sln
├── README.md
├── Guide.md
├── .gitignore
└── LICENSE
/FSTan/Show.fs:
--------------------------------------------------------------------------------
1 | module FSTan.Show
2 | open FSTan.HKT
3 |
4 |
5 | type show<'s> =
6 | interface
7 | abstract member show<'a> : hkt<'s, 'a> -> string
8 | end
9 |
10 | let show<'a, 's when 's :> show<'s>> (a: hkt<'s, 'a>) = getsig<'s>.show a
--------------------------------------------------------------------------------
/FSTan/MonadTrans.fs:
--------------------------------------------------------------------------------
1 | module FSTan.MonadTrans
2 | open FSTan.HKT
3 | open FSTan.Monad
4 |
5 | type monadTrans<'t, 'm when 'm :> monad<'m>> = interface
6 | abstract lift<'a> :
7 | hkt<'m, 'a> -> hkt<'t, 'a>
8 | end
9 |
10 | let lift<'m, 'a, 't when 't :> monadTrans<'t, 'm>> = getsig<'t>.lift<'a>
11 |
--------------------------------------------------------------------------------
/Tutorials/Tutorials.fsproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | netcoreapp2.1
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/FSTan/Functor.fs:
--------------------------------------------------------------------------------
1 | module FSTan.Functor
2 |
3 | open FSTan.HKT
4 |
5 | []
6 | type functor<'F>() =
7 | abstract member fmap<'a, 'b> :
8 | ('a -> 'b) -> hkt<'F, 'a> -> hkt<'F, 'b>
9 | abstract member ``<$``<'a, 'b> : 'a -> hkt<'F, 'b> -> hkt<'F, 'a>
10 | default si.``<$`` a b =
11 | let const' a _ = a
12 | (si.fmap << const') a b
13 |
14 | let fmap<'a, 'b, 'F when 'F :> functor<'F>> :
15 | ('a -> 'b) -> hkt<'F, 'a> -> hkt<'F, 'b> =
16 | getsig<'F>.fmap
17 |
18 |
19 | let ``<$``<'a, 'b, 'F when 'F :> functor<'F> > :
20 | 'a -> hkt<'F, 'b> -> hkt<'F, 'a> = getsig<'F>.``<$``
21 |
22 | let (<<|) a b = ``<$`` a b
--------------------------------------------------------------------------------
/FSTan/FSTan.fsproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/FSTan/Data/Identity.fs:
--------------------------------------------------------------------------------
1 | module FSTan.Data.Identity
2 |
3 | open FSTan.HKT
4 | open FSTan.Monad
5 | open FSTan.Show
6 |
7 | type mkIdentity<'I>() =
8 | inherit monad>()
9 | override __.bind<'a, 'b> (m: hkt, 'a>) (k: 'a -> hkt, 'b>) =
10 | k (unwrap m)
11 |
12 | override __.pure'<'a> (a: 'a) : hkt, 'a> = wrap a
13 | static member wrap<'a> (x : 'a): hkt, 'a> = {wrap = x} :> _
14 | static member unwrap<'a> (x : hkt, 'a>): 'a = (x :?> _).wrap
15 | interface show> with
16 | member __.show (x: hkt, 'a>) =
17 | let x = unwrap x
18 | x.ToString()
19 |
20 | and identityData<'I, 'a> =
21 | {wrap : 'a}
22 | interface hkt, 'a>
23 |
24 |
--------------------------------------------------------------------------------
/FSTan/Data/List.fs:
--------------------------------------------------------------------------------
1 | module FSTan.Data.List
2 |
3 | open FSTan.HKT
4 | open FSTan.Monad
5 | open FSTan.Show
6 |
7 | module List' = List
8 | type List'<'a> = List<'a>
9 |
10 | type mkList<'L>() =
11 | inherit monad>()
12 | static member wrap<'a> (x : List'<'a>): hkt, 'a> =
13 | {wrap = x} :> _
14 | static member unwrap<'a> (x : hkt, 'a>): List'<'a> =
15 | (x :?> _).wrap
16 |
17 | default si.bind<'a, 'b> (m: hkt, 'a>) (k: 'a -> hkt, 'b>): hkt, 'b> =
18 | wrap <| List'.collect (unwrap << k) (unwrap m)
19 |
20 | default si.pure'<'a> (a: 'a): hkt, 'a> = wrap <| [a]
21 | interface show> with
22 | member si.show (x: hkt, 'a>) =
23 | let x = unwrap x
24 | x.ToString()
25 |
26 | and listData<'L, 'a> =
27 | {wrap : List'<'a>}
28 | interface hkt, 'a>
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/FSTan/Data/Either.fs:
--------------------------------------------------------------------------------
1 | module FSTan.Data.Either
2 | open FSTan.HKT
3 | open FSTan.Show
4 | open FSTan.Monad
5 |
6 | type mkEither<'E, 'left>() =
7 | inherit monad>()
8 | default __.pure'<'a> (a: 'a): hkt, 'a> = Right a :> _
9 | default __.bind<'a, 'b> (m: hkt, 'a>) (k: 'a -> hkt, 'b>): hkt, 'b> =
10 | match m :?> eitherData<'E, 'left, 'a> with
11 | | Left l -> Left l :> _
12 | | Right r -> k r
13 | interface show> with
14 | member __.show<'a> (a: hkt, 'a>) =
15 | let a = a :?> eitherData<_, _, _>
16 | a.ToString()
17 |
18 | and eitherData<'E, 'e, 'a> =
19 | | Left of 'e
20 | | Right of 'a
21 | interface hkt, 'a>
22 |
23 | let Left<'E, 'e, 'a> (e: 'e) : hkt, 'a> = Left e :> _
24 | let Right<'E, 'e, 'a> (a: 'a) : hkt, 'a> = Right a :> _
25 | let (|Left|Right|) (m: hkt, 'a>) =
26 | match m :?> eitherData<'E, 'e, 'a> with
27 | | Left l -> Left l
28 | | Right r -> Right r
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/FSTan/Data/Maybe.fs:
--------------------------------------------------------------------------------
1 | module rec FSTan.Data.Maybe
2 |
3 | open FSTan.HKT
4 | open FSTan.Monad
5 | open FSTan.Show
6 |
7 | type mkMaybe<'M>() =
8 | inherit monad>()
9 | override __.bind<'a, 'b> (m: hkt, 'a>) (k: 'a -> hkt, 'b>) =
10 | match unwrap m with
11 | | Some a -> k a
12 | | None -> Nothing
13 |
14 |
15 | override __.pure'<'a> (a: 'a) : hkt, 'a> = wrap <| Some a
16 | static member wrap<'a> (x : Option<'a>): hkt, 'a> = {wrap = x} :> _
17 | static member unwrap<'a> (x : hkt, 'a>): Option<'a> = (x :?> _).wrap
18 | interface show> with
19 | member __.show (a: hkt, 'a>) =
20 | let a = mkMaybe<'M>.unwrap a
21 | a.ToString()
22 |
23 | and OptionWrapper<'M, 'a> =
24 | {wrap : Option<'a>}
25 | interface hkt, 'a>
26 |
27 | let Just<'M, 'a> (a: 'a) : hkt, 'a> = wrap <| Some a
28 |
29 | []
30 | let Nothing<'M, 'a> : hkt, 'a> = wrap <| None
31 |
32 | let (|Just|Nothing|) (m: hkt, 'a>) =
33 | let s: 'a Option = unwrap m
34 | match s with
35 | | Some m -> Just m
36 | | None -> Nothing
37 |
38 |
--------------------------------------------------------------------------------
/FSTan/Monad.fs:
--------------------------------------------------------------------------------
1 | module FSTan.Monad
2 | open FSTan.HKT
3 | open FSTan.Applicative
4 |
5 |
6 | []
7 | type monad<'M>() =
8 | inherit applicative<'M>()
9 | abstract member return'<'a> : 'a -> hkt<'M, 'a>
10 | abstract member bind<'a, 'b> : hkt<'M, 'a> -> ('a -> hkt<'M, 'b>) -> hkt<'M, 'b>
11 | abstract member combine<'a, 'b> :
12 | hkt<'M, 'a> -> hkt<'M, 'b> -> hkt<'M, 'b>
13 |
14 | default si.combine ma mb = si.bind ma <| fun _ -> mb
15 | default si.return' a = si.pure' a
16 |
17 | abstract member fail<'a> : string -> hkt<'M, 'a>
18 | default __.fail s = failwith s
19 |
20 | default si.fmap<'a, 'b> (f : 'a -> 'b) (m : hkt<'M, 'a>) : hkt<'M, 'b> =
21 | si.bind m (f >> si.return')
22 |
23 | let return'<'a, 'M when 'M :> monad<'M>> = getsig<'M>.return'<'a>
24 | let bind<'a, 'b, 'M when 'M :> monad<'M>> = getsig<'M>.bind<'a, 'b>
25 | let (>>=) a b = bind a b
26 | let combine<'a, 'b, 'M when 'M :> monad<'M>> = getsig<'M>.combine<'a, 'b>
27 | let (>>) a b = combine a b
28 |
29 |
30 | type DoNotation() =
31 | member __.Bind(m, k) = bind m k
32 | member __.Return a = return' a
33 | member __.ReturnFrom a = a
34 | member __.Combine ma mb = combine ma mb
35 | // TODO: forM
36 |
37 | let Do = DoNotation()
--------------------------------------------------------------------------------
/FSTan/Monoid.fs:
--------------------------------------------------------------------------------
1 | module FSTan.Monoid
2 | open FSTan.HKT
3 |
4 | []
5 | type semigroup<'s>() =
6 |
7 | abstract member op<'a> :
8 | hkt<'s, 'a> -> hkt<'s, 'a> -> hkt<'s, 'a>
9 | abstract member sconcat<'a> :
10 | hkt<'s, 'a> -> hkt<'s, 'a>
11 | abstract member stimes<'a> :
12 | int -> hkt<'s, 'a> -> hkt<'s, 'a>
13 |
14 | default si.stimes a b = semigroup<'s>.stimesDefault si a b
15 |
16 | static member stimesDefault si y0 x0 =
17 | if y0 <= 0
18 | then failwith "stimes: positive multiplier expected"
19 | else
20 | let rec f x y =
21 | match y with
22 | | _ when y%2 = 0 ->
23 | f (si.op x x) (y / 2)
24 | | 1 -> x
25 | | _ -> g (si.op x x) (y / 2) x
26 | and g x y z =
27 | match y with
28 | | _ when y%2 = 0 ->
29 | g (si.op x x) (y / 2) z
30 | | 1 -> si.op x z
31 | | _ -> g (si.op x x) (y / 2) (si.op x z)
32 | in f x0 y0
33 |
34 |
35 | []
36 | type monoid<'s>() =
37 | inherit semigroup<'s>()
38 | abstract member mempty<'m> : unit -> hkt<'s, 'm>
39 | abstract member mappend<'m> : hkt<'s, 'm> -> hkt<'s, 'm> -> hkt<'s, 'm>
40 | abstract member mconcat<'m> : hkt<'s, 'm> list -> hkt<'s, 'm>
41 |
42 | default si.mappend a b =
43 | si.op a b
44 |
45 | default si.mconcat xs =
46 | let empty = si.mempty()
47 | List.foldBack si.mappend xs empty
--------------------------------------------------------------------------------
/FSTan.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.28307.168
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSTan", "FSTan\FSTan.fsproj", "{79E22A01-CABB-4731-BE2C-652F6012304C}"
7 | EndProject
8 | Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Tutorials", "Tutorials\Tutorials.fsproj", "{1A608D0F-5165-409B-B366-51302F216FD2}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Release|Any CPU = Release|Any CPU
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {79E22A01-CABB-4731-BE2C-652F6012304C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17 | {79E22A01-CABB-4731-BE2C-652F6012304C}.Debug|Any CPU.Build.0 = Debug|Any CPU
18 | {79E22A01-CABB-4731-BE2C-652F6012304C}.Release|Any CPU.ActiveCfg = Release|Any CPU
19 | {79E22A01-CABB-4731-BE2C-652F6012304C}.Release|Any CPU.Build.0 = Release|Any CPU
20 | {1A608D0F-5165-409B-B366-51302F216FD2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {1A608D0F-5165-409B-B366-51302F216FD2}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {1A608D0F-5165-409B-B366-51302F216FD2}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {1A608D0F-5165-409B-B366-51302F216FD2}.Release|Any CPU.Build.0 = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {65DDB457-5650-41DE-AB9D-3FB0EB1C0985}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/FSTan/HKT.fs:
--------------------------------------------------------------------------------
1 | module FSTan.HKT
2 | type hkt<'K, 'T> = interface end
3 |
4 | open System
5 | open System.Reflection
6 |
7 | let private ts = Array.zeroCreate 0
8 |
9 | []
10 | let getsig<'a> =
11 | // There is another way to do so: add constraint
12 | // `'a when 'a: (new: unit -> 'a)`.
13 | // However, if this way is adopted, users have to
14 | // manually mark each generic typevar of a type constructor,
15 | // which could be verbose and annoying.
16 | // With above considerations, I use reflection instead.
17 | let t = typeof<'a>
18 | let f = t.GetConstructor(
19 | BindingFlags.Instance ||| BindingFlags.Public,
20 | null,
21 | CallingConventions.HasThis,
22 | ts,
23 | null)
24 | let o = f.Invoke([||])
25 | o :?> 'a
26 |
27 |
28 | // Some builtin data types like Map, List, Option cannot be interfaced
29 | // with `hkt`, so we have to wrap them.
30 | // Following methods provide a common interface to access `wrap` and `unwrap`
31 | // operations for all wrapped types.
32 | // Also, following methods implement a core infrastructure introduced from this paper:
33 | // https://www.cl.cam.ac.uk/~jdy22/papers/lightweight-higher-kinded-polymorphism.pdf
34 | // `wrap` here is a polymorphic `inj` in that paper and `unwrap` is a polymorphic `prj`.
35 |
36 | let inline wrap<'o, ^f, 'a when ^f : (static member wrap : 'o -> hkt<'f, 'a>)> (o: 'o) : hkt< ^f, 'a> =
37 | (^f : (static member wrap : 'o -> hkt<'f, 'a>) o)
38 |
39 | let inline unwrap<'o, ^f, 'a when ^f : (static member unwrap : hkt<'f, 'a> -> 'o)> (f : hkt< ^f, 'a>) : 'o =
40 | (^f : (static member unwrap : hkt<'f, 'a> -> 'o) f)
--------------------------------------------------------------------------------
/FSTan/Applicative.fs:
--------------------------------------------------------------------------------
1 | module FSTan.Applicative
2 | open FSTan.HKT
3 | open FSTan.Functor
4 |
5 | []
6 | type applicative<'F>() =
7 | inherit functor<'F>()
8 |
9 | abstract member pure'<'a> : 'a -> hkt<'F, 'a>
10 |
11 | abstract member ap<'a, 'b> : hkt<'F, ('a -> 'b)> -> hkt<'F, 'a> -> hkt<'F, 'b>
12 | default si.ap f a = si.liftA2 id f a
13 |
14 | abstract member liftA2<'a, 'b, 'c> :
15 | ('a -> 'b -> 'c) -> hkt<'F, 'a> -> hkt<'F, 'b> -> hkt<'F, 'c>
16 |
17 | default si.liftA2<'a, 'b, 'c> (f: 'a -> 'b -> 'c) (x: hkt<'F, 'a>) (y: hkt<'F, 'b>) =
18 | si.ap (si.fmap f x) y
19 |
20 | abstract member ``*>``<'a, 'b> : hkt<'F, 'a> -> hkt<'F, 'b> -> hkt<'F, 'b>
21 | default si.``*>``<'a, 'b> (a1: hkt<'F, 'a>) (a2: hkt<'F, 'b>): hkt<'F, 'b> =
22 | si.ap (si.``<$`` id a1) a2
23 |
24 | abstract member ``<*`` : hkt<'F, 'a> -> hkt<'F, 'b> -> hkt<'F, 'a>
25 | default si.``<*`` a b = si.liftA2 (fun x _ -> x) a b
26 |
27 |
28 | let pure'<'a, 'F when 'F :> applicative<'F>> :
29 | 'a -> hkt<'F, 'a> =
30 | getsig<'F>.pure'<'a>
31 |
32 | let ap<'a, 'b, 'F when 'F :> applicative<'F>> :
33 | hkt<'F, ('a -> 'b)> -> hkt<'F, 'a> -> hkt<'F, 'b> =
34 | getsig<'F>.ap<'a, 'b>
35 |
36 | let (<*>) a b = ap a b
37 |
38 | let liftA<'a, 'b, 'F when 'F :> applicative<'F>>
39 | (f : 'a -> 'b) (a : hkt<'F, 'a>) : hkt<'F, 'b>
40 | = let si = getsig<'F> in
41 | si.pure' f <*> a
42 |
43 | let liftA2<'a, 'b, 'c, 'F when 'F :> applicative<'F>> :
44 | ('a -> 'b -> 'c) -> hkt<'F, 'a> -> hkt<'F, 'b> -> hkt<'F, 'c>
45 | = getsig<'F>.liftA2
46 |
47 | let ``<*``<'a, 'b, 'F when 'F :> applicative<'F>> :
48 | hkt<'F, 'a> -> hkt<'F, 'b> -> hkt<'F, 'a> =
49 | getsig<'F>.``<*``
50 |
51 | let (<*) a b = ``<*`` a b
52 |
53 |
54 | let ``*>``<'a, 'b, 'F when 'F :> applicative<'F>> :
55 | hkt<'F, 'a> -> hkt<'F, 'b> -> hkt<'F, 'b> =
56 | getsig<'F>.``*>``
57 |
58 | let ( *> ) a b = ``*>`` a b
59 |
60 | // TODO, liftA3
--------------------------------------------------------------------------------
/FSTan/Control/Trans/State.fs:
--------------------------------------------------------------------------------
1 | module rec FSTan.Control.Trans.State
2 | open FSTan.HKT
3 | open FSTan.Monad
4 | open FSTan.MonadTrans
5 |
6 | type mkStateTras<'ST, 's, 'm when 'm :> monad<'m>>() =
7 | inherit monad>()
8 | default si.pure'<'a> (a: 'a): hkt, 'a> =
9 | StateT <| fun s -> return' (a, s)
10 |
11 | override si.bind<'a, 'b>
12 | (m: hkt, 'a>)
13 | (k: 'a -> hkt, 'b>): hkt, 'b> =
14 | StateT <| fun s ->
15 | runStateT m s >>= fun (a, s') ->
16 | runStateT (k a) s'
17 |
18 | interface hkt<'s, 'm>
19 | interface monadTrans, 'm> with
20 | member si.lift<'a> (m: hkt<'m, 'a>): hkt, 'a> =
21 | StateT <| fun (s: 's) ->
22 | m >>= fun a -> return' (a, s)
23 |
24 | and stateTData<'ST, 's, 'm, 'a when 'm :> monad<'m>> =
25 | | StateT' of ('s -> hkt<'m, ('a * 's)>)
26 | interface hkt, 'a>
27 |
28 | let runStateT<'ST, 's, 'm, 'a when 'm :> monad<'m>> (m: hkt, 'a>): ('s -> hkt<'m, ('a * 's)>) =
29 | let (StateT' f) = m :?> stateTData<'ST, 's, 'm, 'a>
30 | f
31 |
32 | let StateT<'ST, 's, 'm, 'a when 'm :> monad<'m>> (f: 's -> hkt<'m, 'a * 's>) : hkt, 'a> =
33 | (StateT' f) :> _
34 |
35 | let (|StateT|) (m: hkt, 'a>) =
36 | let (StateT' f) = m :?> stateTData<'ST, 's, 'm, 'a>
37 | in StateT f
38 |
39 | let state f = StateT (return' << f)
40 |
41 | let get<'ST, 's, 'm when 'm :> monad<'m>> : hkt, 's> =
42 | state <| fun s -> (s, s)
43 |
44 | let put<'ST, 's, 'm when 'm :> monad<'m>> (s: 's) : hkt, unit> =
45 | state <| fun _ -> (), s
46 |
47 | let modify f = state <| fun s -> (), f s
48 |
49 | let gets f = state <| fun s -> f s, s
50 |
51 | let evalStateT<'ST, 's, 'm, 'a when 'm :> monad<'m>> : hkt, 'a> -> 's -> hkt<'m, 'a> =
52 | fun m s -> Do {
53 | let! (a, _) = runStateT m s
54 | return a
55 | }
56 |
57 | let execStateT<'ST, 's, 'm, 'a when 'm :> monad<'m>> : hkt, 'a> -> 's -> hkt<'m, 's> =
58 | fun m s -> Do {
59 | let! (_, s) = runStateT m s
60 | return s
61 | }
--------------------------------------------------------------------------------
/FSTan/Control/State.fs:
--------------------------------------------------------------------------------
1 | module rec FSTan.Control.State
2 |
3 | open FSTan.HKT
4 |
5 | open FSTan.Monad
6 | open FSTan.Data.Identity
7 | open FSTan.Control.Trans
8 |
9 | module StateT = FSTan.Control.Trans.State
10 |
11 | type S_Id() =
12 | inherit mkIdentity()
13 |
14 | type mkState<'ST, 's> = StateT.mkStateTras<'ST, 's, mkIdentity>
15 |
16 | []
17 | let runState<'ST, 's, 'a>(m: hkt, 'a>): ('s -> 'a * 's) =
18 | let f = StateT.runStateT m
19 | fun s -> S_Id.unwrap (f s)
20 |
21 | let State<'ST, 's, 'a> (f: 's -> ('a * 's)): hkt, 'a> =
22 | let f = fun s -> S_Id.wrap (f s)
23 | StateT.StateT f
24 |
25 | let (|State|) (s: hkt, 'a>) =
26 | let (StateT.StateT f) = s
27 | in State (fun s -> S_Id.unwrap (f s))
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # FSTan
2 |
3 | Exactly a full-featured and practical implementation typeclasses and higher kinded types in F#.
4 |
5 | For manuals check [Guide.md](https://github.com/thautwarm/FSTan/blob/master/Guide.md), where you'll be told how to use these concise typeclasses, higher kinded types and constraints.
6 |
7 |
8 |
9 | ## Motivation and Features
10 |
11 | There are also other similar implementations in FSharp like `Higher` and `FSharpPlus`, but they're not able to provide all the features listed below, which motivate me to create a better one:
12 |
13 | - Support instance resolution.
14 | - Support ad-hoc polymorphism.
15 | - Support to create a typeclass and add constraints to it.
16 | - Support subtypeclassing.
17 | - Support to directly access type constructor.
18 | - Support default implementations for typeclass.
19 | - All above operations are quite lightweighted and not implemented in a magic way.
20 |
21 | Yes, exactly, it's a what many and I have dreamed about for so long.
22 |
23 |
24 | ## Limitation
25 |
26 | 1. The performance might hurt in some scenarios, for each the datatype works with
27 | higher kinded types have to be upcasted to an unique abstract class, for instance,
28 | `maybe<'a>` has to be casted to `hkt`.
29 |
30 | 2. For some builtin datatypes cannot be interfaced with `hkt`, an extra wrapper class is
31 | required to work with higher kined types.
32 |
33 | For instance, interface type `listData<'a>` is required for the builtin `List<'a>`.
34 |
35 | You can use `wrap` and `unwrap` to transform datatypes from `List<'a>` to `hkt,'a>`, vice versa.
36 |
37 | ```FSharp
38 | module List' = List
39 | type List'<'a> = List<'a>
40 |
41 |
42 | type mkList<'L>() =
43 | inherit monad>()
44 | static member wrap<'a> (x : List'<'a>): hkt, 'a> =
45 | {wrap = x} :> _
46 | static member unwrap<'a> (x : hkt, 'a>): List'<'a> =
47 | (x :?> _).wrap
48 |
49 | default si.bind<'a, 'b> (m: hkt, 'a>) (k: 'a -> hkt, 'b>): hkt, 'b> =
50 | wrap <| List'.collect (unwrap << k) (unwrap m)
51 |
52 | default si.pure'<'a> (a: 'a): hkt, 'a> = wrap <| [a]
53 | interface show> with
54 | member si.show (x: hkt, 'a>) =
55 | let x = unwrap x
56 | x.ToString()
57 |
58 | and listData<'L, 'a> =
59 | {wrap : List'<'a>}
60 | interface hkt, 'a>
61 |
62 |
63 | // create a concrete List type
64 | type ListSig() =
65 | // default implements following type classes:
66 | // - monad (functor and applicative are implemented simultaneously)
67 | // - show
68 |
69 | inherit mkList()
70 | type list<'a> = hkt, 'a>
71 |
72 | let test() =
73 |
74 | let listm: _ list = Do {
75 | let! x = wrap [1, 2, 3]
76 | wrap [x]
77 | }
78 | // listm : resolved to be list
79 |
80 | let f (x: int) : string = ""
81 | fmap f listm
82 | // return value is resolved to be list
83 | ```
84 | 3. Cannot implement instance for datatypes that are not constructed by a type constructor.
85 | For instance, you cannot implement any typeclass for all primitives types like integers, floats and so on, unless you wrap them with an `Identity` type constructor.
86 |
87 |
--------------------------------------------------------------------------------
/Tutorials/Program.fs:
--------------------------------------------------------------------------------
1 | // Learn more about F# at http://fsharp.org
2 |
3 | open System
4 |
5 | open FSTan.HKT
6 |
7 | // define a simple typeclass
8 | []
9 | type show<'s>() =
10 | abstract member show<'a> : hkt<'s, 'a> -> string
11 |
12 | let show<'a, 's when 's :> show<'s>> = getsig<'s>.show<'a>
13 |
14 | type myData1<'a> = // define datatype
15 | | A | B | C
16 | interface hkt
17 |
18 | and MyTypeCons1() =
19 | // define type constructor
20 | // in F#, we don't really have this, but
21 | // we can leverage a signature type(yes, this is just a signature)
22 | // and `hkt`(check FSTan.HKT, not magic at all)
23 | // to fully simulate a type constructor.
24 | inherit show() with
25 | override si.show a =
26 | // This conversion can absolutely succeed
27 | // for there is only one datatype which
28 | // interfaces hkt
29 | let a = a :?> _ myData1
30 |
31 | sprintf "%A" a
32 |
33 |
34 | type myData2<'a> = // define datatype
35 | | I of int
36 | | S of string
37 | interface hkt
38 | and MyTypeCons2() =
39 | // define type constructor
40 | // in F#, we don't really have this, but
41 | // we can leverage a signature type(yes, this is just a signature)
42 | // and `hkt`(check FSTan.HKT, not magic at all)
43 | // to fully simulate a type constructor.
44 | inherit show() with
45 | override si.show a =
46 | let a = a :?> _ myData2
47 | match a with
48 | | I a -> sprintf "isInt %d" a
49 | | S a -> sprintf "isStr %s" a
50 |
51 |
52 | let test() =
53 | let s1 = show <| I 32
54 | let s2 = show <| S "123"
55 | let s3 = show A
56 | let s4 = show B
57 | printfn "%s\n%s\n%s\n%s" s1 s2 s3 s4
58 |
59 | open FSTan.Monad
60 | open FSTan.Data.Maybe
61 | open FSTan.Data.List
62 | open FSTan.Control.State
63 | open FSTan.Data.Either
64 | open FSTan.Control.Trans.State
65 | open FSTan.MonadTrans
66 |
67 |
68 | type ListSig() =
69 | inherit mkList()
70 |
71 | type List = mkList
72 |
73 | type EitherSig<'e>() =
74 | inherit mkEither, 'e>()
75 | type Either<'e> = mkEither, 'e>
76 |
77 |
78 | type StateSig<'s>() =
79 | inherit mkState, 's>()
80 | type State<'s> = mkState, 's>
81 |
82 |
83 | type MaybeSig() =
84 | inherit mkMaybe()
85 |
86 | type Maybe = mkMaybe
87 |
88 |
89 | type either<'e, 'a> = hkt, 'a>
90 | type maybe<'a> = hkt
91 | type state<'s, 'a> = hkt, 'a>
92 | type list<'a> = hkt
93 |
94 | type S() =
95 | member __.s (x: int) = x + 1
96 |
97 | let inline app< ^F, 'a, 'c when ^F: (static member cons: 'a -> 'c)> : ^F -> 'a -> 'c = fun F a ->
98 | (^F: (static member cons: 'a -> 'c) a)
99 |
100 | open FSTan.Monad
101 | open FSTan.Control.Trans.State
102 |
103 |
104 |
105 |
106 | type StateTransSig<'s, 'm when 'm :> monad<'m>>() =
107 | inherit mkStateTras, 's, 'm>()
108 |
109 | type stateT<'s, 'm, 'a when 'm :> monad<'m>> = hkt, 's, 'm>, 'a>
110 |
111 | let plusOne<'m when 'm :> monad<'m>> : stateT = Do {
112 | let! state = get // similar to `state <- get` in haskell
113 | do! put <| state + 1
114 | return ()
115 | }
116 |
117 | let testMaybe(): stateT = plusOne
118 | let testEither<'a> : stateT, unit> = plusOne
119 |
120 | []
121 | let main argv =
122 | test()
123 |
124 | let m1 =
125 | Do {
126 | let! x = Just 1
127 | return ""
128 | }
129 |
130 | let m2 : _ list =
131 | Do {
132 | let! x = wrap [1; 2; 3]
133 | return x * 3
134 | }
135 |
136 | //let m3: state =
137 | // Do {
138 | // let! s = get
139 | // return s + 1
140 | // }
141 | //let a, b = runState m3 1
142 |
143 | let f = Right 1
144 | let m4 : either -> either = fun m ->
145 | Do {
146 | let! a = m
147 | return a + 1
148 | }
149 |
150 | let (Right 2) = m4 f
151 |
152 | let m4: stateT = Do {
153 | let! a = lift <| Just 1
154 | let! s = get
155 | return a
156 | }
157 |
158 | let s = runStateT plusOne 1
159 |
160 |
161 | 0 // return an integer exit code
162 |
--------------------------------------------------------------------------------
/Guide.md:
--------------------------------------------------------------------------------
1 | # FSTan Guide
2 |
3 |
4 | Typeclasses
5 | =============
6 |
7 |
8 | Typeclassess are achived through abstract classes, which makes it works perfect for both subtypeclassing and default implementations.
9 |
10 | If some type is constructed with a type constructor, you can implement `show` class for it.
11 |
12 | Let's have a look at how to write a `show` class and use it in polymorphism functions and even operators.
13 |
14 |
15 | ```FSharp
16 |
17 | open FSTan.HKT
18 |
19 | // define a simple typeclass
20 | []
21 | type show<'s>() =
22 | abstract member show<'a> : hkt<'s, 'a> -> string
23 |
24 | // I have a typeclass,
25 | // I have 2 datatypes,
26 | // Oh!
27 | // Polymorphism!
28 | let show<'a, 's when 's :> show<'s>> = getsig<'s>.show<'a>
29 |
30 | type myData1<'a> = // define datatype
31 | | A | B | C
32 | interface hkt
33 |
34 | and MyTypeCons1() =
35 | // define type constructor
36 | // in F#, we don't really have this, but
37 | // we can leverage a signature type(yes, this is just a signature)
38 | // and `hkt`(check FSTan.HKT, not magic at all)
39 | // to fully simulate a type constructor.
40 | inherit show() with
41 | override si.show a =
42 | // This conversion can absolutely succeed
43 | // for there is only one datatype which
44 | // interfaces hkt
45 | let a = a :?> _ myData1
46 |
47 | sprintf "%A" a
48 |
49 |
50 | type myData2<'a> = // define datatype
51 | | I of int
52 | | S of string
53 | interface hkt
54 | and MyTypeCons2() =
55 | // define type constructor
56 | // in F#, we don't really have this, but
57 | // we can leverage a signature type(yes, this is just a signature)
58 | // and `hkt`(check FSTan.HKT, not magic at all)
59 | // to fully simulate a type constructor.
60 | inherit show() with
61 | override si.show a =
62 | let a = a :?> _ myData2
63 | match a with
64 | | I a -> sprintf "isInt %d" a
65 | | S a -> sprintf "isStr %s" a
66 | let test() =
67 | let s1 = show <| I 32
68 | let s2 = show <| S "123"
69 | let s3 = show A
70 | let s4 = show B
71 | printfn "%s\n%s\n%s\n%s" s1 s2 s3 s4
72 |
73 | ```
74 | Output:
75 | ```
76 | isInt 32
77 | isStr 123
78 | A
79 | B
80 | ```
81 |
82 |
83 | Subtypeclassing
84 | =============
85 |
86 | If you're familiar with Haskell and related stuffs, you must have an experience with this case:
87 |
88 | ```haskell
89 |
90 | class Applicative m => Monad m where
91 | -- descriptions of monad typeclass
92 | ```
93 |
94 | Above code descibes the an example of dependencies between typeclasses, and `Monad`
95 | is exactly a subtypeclass of `Applicative`.
96 |
97 | After introducing this sort of constraints, a higher level abstraction is achieved, which enables reaching a higher ratio of code reuse.
98 |
99 | For instance, a `Monad` instance requires implementations of many specific methods(`return`, `bind`, `combine` and so on), but we already have a knowledge about subtypeclassing information of `Monad`, it's a subtypeclass of `Functor` and `Applicative`, so if we implement `pure` from `Applicative` and implement `bind` from `Monad` for an instance(eg. `Maybe`) of `Monad`, we then implement all instances of `Functor`, `Applicative` and `Monad`.
100 |
101 | In F#, we can implement `Either` `Monad`(also `Functor` and `Applicative`).
102 |
103 | ```FSharp
104 | open FSTan.HKT
105 | open FSTan.Show
106 | open FSTan.Monad
107 |
108 | type either<'e, 'a> = hkt, 'a>
109 |
110 | and EitherMonad<'e>() =
111 | inherit monad>() with
112 | override __.pure'<'a> (a: 'a): either<'e, 'a> = Right a :> _
113 | override __.bind<'a, 'b> (m: either<'e, 'a>) (k: 'a -> either<'e, 'b>): either<'e, 'b> =
114 | match m :?> eitherData<'e, 'a> with
115 | | Left l -> Left l :> _
116 | | Right r -> k r
117 | interface show> with
118 | member __.show<'a> (a: either<'e, 'a>) =
119 | let a = a :?> eitherData<_, _>
120 | a.ToString()
121 |
122 | and eitherData<'e, 'a> =
123 | | Left of 'e
124 | | Right of 'a
125 | interface either<'e, 'a>
126 |
127 | let Left<'e, 'a> (e: 'e) : either<'e, 'a> = Left e :> _
128 | let Right<'e, 'a> (a: 'a) : either<'e, 'a> = Right a :> _
129 | let (|Left|Right|) (m: either<'e, 'a>) =
130 | match m :?> eitherData<'e, 'a> with
131 | | Left l -> Left l
132 | | Right r -> Right r
133 | ```
134 |
135 | Abobe codes in Haskell is similar to
136 |
137 | ```Haskell
138 |
139 | data Either e a = Left e | Right a
140 |
141 | instance Functor (Either e) where
142 | -- ... `fmap` and other "methods" are automatically implemented by `bind` and `return`.
143 |
144 | instance Applicative (Either e) where
145 | pure = Right
146 | -- ...
147 |
148 | instance Monad (Either e) where
149 | return = pure
150 | bind m k = \case
151 | Left l -> Left l
152 | Right r -> k r
153 |
154 | instance Show (Either e a) where
155 | -- this section is not that similar to haskell
156 | ```
157 |
158 | Feel free to check [implementation of `Monad` in FSTan](https://github.com/thautwarm/FSTan/blob/master/FSTan/Monad.fs).
159 |
160 |
161 |
162 | Higher kined types
163 | ==================
164 |
165 | ```FSharp
166 | let test_hkt<'a, 'b, 'c> (f: hkt<'a, 'b>) : hkt<'b, 'c> =
167 | /// impl
168 | ```
169 |
170 | In terms of above snippet, if `c` is a concrete type, then `'a` has kind `* -> * -> *`, as well as `b` has kind `* -> *`.
171 |
172 |
173 | Do notation
174 | =====================
175 |
176 | Open `FSTan.Monad`, where a computation expression is provided to be an alternative of `do` in Haskell.
177 |
178 | ```FSharp
179 |
180 | open FSTan.Monad
181 | open FSTan.Control.Trans.State
182 | open FSTan.Data.Maybe
183 | open FSTan.Data.Either
184 |
185 | let plusOne<'m when 'm :> monad<'m>> : stateT = Do {
186 | let! state = get // similar to `state <- get` in haskell
187 | do! put <| state + 1
188 | return ()
189 | }
190 |
191 | let valueMaybe : stateT = plusOne
192 | // type maybe<'a> = hkt
193 |
194 | let valueEither<'e> : stateT, unit> = plusOne
195 | // type either<'e, 'a> = hkt, 'a>
196 | ```
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.suo
8 | *.user
9 | *.userosscache
10 | *.sln.docstates
11 |
12 | # User-specific files (MonoDevelop/Xamarin Studio)
13 | *.userprefs
14 |
15 | # Build results
16 | [Dd]ebug/
17 | [Dd]ebugPublic/
18 | [Rr]elease/
19 | [Rr]eleases/
20 | x64/
21 | x86/
22 | bld/
23 | [Bb]in/
24 | [Oo]bj/
25 | [Ll]og/
26 |
27 | # Visual Studio 2015/2017 cache/options directory
28 | .vs/
29 | # Uncomment if you have tasks that create the project's static files in wwwroot
30 | #wwwroot/
31 |
32 | # Visual Studio 2017 auto generated files
33 | Generated\ Files/
34 |
35 | # MSTest test Results
36 | [Tt]est[Rr]esult*/
37 | [Bb]uild[Ll]og.*
38 |
39 | # NUNIT
40 | *.VisualState.xml
41 | TestResult.xml
42 |
43 | # Build Results of an ATL Project
44 | [Dd]ebugPS/
45 | [Rr]eleasePS/
46 | dlldata.c
47 |
48 | # Benchmark Results
49 | BenchmarkDotNet.Artifacts/
50 |
51 | # .NET Core
52 | project.lock.json
53 | project.fragment.lock.json
54 | artifacts/
55 | **/Properties/launchSettings.json
56 |
57 | # StyleCop
58 | StyleCopReport.xml
59 |
60 | # Files built by Visual Studio
61 | *_i.c
62 | *_p.c
63 | *_i.h
64 | *.ilk
65 | *.meta
66 | *.obj
67 | *.iobj
68 | *.pch
69 | *.pdb
70 | *.ipdb
71 | *.pgc
72 | *.pgd
73 | *.rsp
74 | *.sbr
75 | *.tlb
76 | *.tli
77 | *.tlh
78 | *.tmp
79 | *.tmp_proj
80 | *.log
81 | *.vspscc
82 | *.vssscc
83 | .builds
84 | *.pidb
85 | *.svclog
86 | *.scc
87 |
88 | # Chutzpah Test files
89 | _Chutzpah*
90 |
91 | # Visual C++ cache files
92 | ipch/
93 | *.aps
94 | *.ncb
95 | *.opendb
96 | *.opensdf
97 | *.sdf
98 | *.cachefile
99 | *.VC.db
100 | *.VC.VC.opendb
101 |
102 | # Visual Studio profiler
103 | *.psess
104 | *.vsp
105 | *.vspx
106 | *.sap
107 |
108 | # Visual Studio Trace Files
109 | *.e2e
110 |
111 | # TFS 2012 Local Workspace
112 | $tf/
113 |
114 | # Guidance Automation Toolkit
115 | *.gpState
116 |
117 | # ReSharper is a .NET coding add-in
118 | _ReSharper*/
119 | *.[Rr]e[Ss]harper
120 | *.DotSettings.user
121 |
122 | # JustCode is a .NET coding add-in
123 | .JustCode
124 |
125 | # TeamCity is a build add-in
126 | _TeamCity*
127 |
128 | # DotCover is a Code Coverage Tool
129 | *.dotCover
130 |
131 | # AxoCover is a Code Coverage Tool
132 | .axoCover/*
133 | !.axoCover/settings.json
134 |
135 | # Visual Studio code coverage results
136 | *.coverage
137 | *.coveragexml
138 |
139 | # NCrunch
140 | _NCrunch_*
141 | .*crunch*.local.xml
142 | nCrunchTemp_*
143 |
144 | # MightyMoose
145 | *.mm.*
146 | AutoTest.Net/
147 |
148 | # Web workbench (sass)
149 | .sass-cache/
150 |
151 | # Installshield output folder
152 | [Ee]xpress/
153 |
154 | # DocProject is a documentation generator add-in
155 | DocProject/buildhelp/
156 | DocProject/Help/*.HxT
157 | DocProject/Help/*.HxC
158 | DocProject/Help/*.hhc
159 | DocProject/Help/*.hhk
160 | DocProject/Help/*.hhp
161 | DocProject/Help/Html2
162 | DocProject/Help/html
163 |
164 | # Click-Once directory
165 | publish/
166 |
167 | # Publish Web Output
168 | *.[Pp]ublish.xml
169 | *.azurePubxml
170 | # Note: Comment the next line if you want to checkin your web deploy settings,
171 | # but database connection strings (with potential passwords) will be unencrypted
172 | *.pubxml
173 | *.publishproj
174 |
175 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
176 | # checkin your Azure Web App publish settings, but sensitive information contained
177 | # in these scripts will be unencrypted
178 | PublishScripts/
179 |
180 | # NuGet Packages
181 | *.nupkg
182 | # The packages folder can be ignored because of Package Restore
183 | **/[Pp]ackages/*
184 | # except build/, which is used as an MSBuild target.
185 | !**/[Pp]ackages/build/
186 | # Uncomment if necessary however generally it will be regenerated when needed
187 | #!**/[Pp]ackages/repositories.config
188 | # NuGet v3's project.json files produces more ignorable files
189 | *.nuget.props
190 | *.nuget.targets
191 |
192 | # Microsoft Azure Build Output
193 | csx/
194 | *.build.csdef
195 |
196 | # Microsoft Azure Emulator
197 | ecf/
198 | rcf/
199 |
200 | # Windows Store app package directories and files
201 | AppPackages/
202 | BundleArtifacts/
203 | Package.StoreAssociation.xml
204 | _pkginfo.txt
205 | *.appx
206 |
207 | # Visual Studio cache files
208 | # files ending in .cache can be ignored
209 | *.[Cc]ache
210 | # but keep track of directories ending in .cache
211 | !*.[Cc]ache/
212 |
213 | # Others
214 | ClientBin/
215 | ~$*
216 | *~
217 | *.dbmdl
218 | *.dbproj.schemaview
219 | *.jfm
220 | *.pfx
221 | *.publishsettings
222 | orleans.codegen.cs
223 |
224 | # Including strong name files can present a security risk
225 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
226 | #*.snk
227 |
228 | # Since there are multiple workflows, uncomment next line to ignore bower_components
229 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
230 | #bower_components/
231 |
232 | # RIA/Silverlight projects
233 | Generated_Code/
234 |
235 | # Backup & report files from converting an old project file
236 | # to a newer Visual Studio version. Backup files are not needed,
237 | # because we have git ;-)
238 | _UpgradeReport_Files/
239 | Backup*/
240 | UpgradeLog*.XML
241 | UpgradeLog*.htm
242 | ServiceFabricBackup/
243 | *.rptproj.bak
244 |
245 | # SQL Server files
246 | *.mdf
247 | *.ldf
248 | *.ndf
249 |
250 | # Business Intelligence projects
251 | *.rdl.data
252 | *.bim.layout
253 | *.bim_*.settings
254 | *.rptproj.rsuser
255 |
256 | # Microsoft Fakes
257 | FakesAssemblies/
258 |
259 | # GhostDoc plugin setting file
260 | *.GhostDoc.xml
261 |
262 | # Node.js Tools for Visual Studio
263 | .ntvs_analysis.dat
264 | node_modules/
265 |
266 | # Visual Studio 6 build log
267 | *.plg
268 |
269 | # Visual Studio 6 workspace options file
270 | *.opt
271 |
272 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
273 | *.vbw
274 |
275 | # Visual Studio LightSwitch build output
276 | **/*.HTMLClient/GeneratedArtifacts
277 | **/*.DesktopClient/GeneratedArtifacts
278 | **/*.DesktopClient/ModelManifest.xml
279 | **/*.Server/GeneratedArtifacts
280 | **/*.Server/ModelManifest.xml
281 | _Pvt_Extensions
282 |
283 | # Paket dependency manager
284 | .paket/paket.exe
285 | paket-files/
286 |
287 | # FAKE - F# Make
288 | .fake/
289 |
290 | # JetBrains Rider
291 | .idea/
292 | *.sln.iml
293 |
294 | # CodeRush
295 | .cr/
296 |
297 | # Python Tools for Visual Studio (PTVS)
298 | __pycache__/
299 | *.pyc
300 |
301 | # Cake - Uncomment if you are using it
302 | # tools/**
303 | # !tools/packages.config
304 |
305 | # Tabs Studio
306 | *.tss
307 |
308 | # Telerik's JustMock configuration file
309 | *.jmconfig
310 |
311 | # BizTalk build output
312 | *.btp.cs
313 | *.btm.cs
314 | *.odx.cs
315 | *.xsd.cs
316 |
317 | # OpenCover UI analysis results
318 | OpenCover/
319 |
320 | # Azure Stream Analytics local run output
321 | ASALocalRun/
322 |
323 | # MSBuild Binary and Structured Log
324 | *.binlog
325 |
326 | # NVidia Nsight GPU debugger configuration file
327 | *.nvuser
328 |
329 | # MFractors (Xamarin productivity tool) working folder
330 | .mfractor/
331 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------