├── .gitignore
├── Applying_and_Evaluating_Functional_Programming_Paradigms_and_Techniques_in_Developing_Games.pdf
├── PracticalLanguageExt.pdf
├── Program.cs
├── README.md
├── The Language Ext Tutorial.pdf
├── Tutorial01_monad
├── Box.cs
├── Program.cs
└── Tutorial01 - Monad.csproj
├── Tutorial02_transformations_1
├── Box.cs
├── Program.cs
└── Tutorial02 - Transformations 1.csproj
├── Tutorial03_pipelines
├── Box.cs
├── Program.cs
└── Tutorial03 - Pipelines.csproj
├── Tutorial04_methods_1
├── Box.cs
├── Program.cs
└── Tutorial04 - Methods 1.csproj
├── Tutorial05_methods_2
├── Box.cs
├── Program.cs
└── Tutorial05 - Methods 2.csproj
├── Tutorial06_Linq
├── Box.cs
├── Program.cs
└── Tutorial06 - Linq.csproj
├── Tutorial07_transformations_2
├── Box.cs
├── Program.cs
└── Tutorial07 - Transformations 2.csproj
├── Tutorial08_declarative_style
├── Box.cs
├── Program.cs
└── Tutorial08 - Declarative style.csproj
├── Tutorial09_automatic_validation
├── Box.cs
├── Program.cs
└── Tutorial09 - automatic validation.csproj
├── Tutorial10_returning_monads
├── Box.cs
├── Program.cs
└── Tutorial10 - returning monads.csproj
├── Tutorial11_short_circuiting
├── Box.cs
├── Program.cs
└── Tutorial11 - short circuiting.csproj
├── Tutorial12_function_compositionial12
├── Box.cs
├── Program.cs
└── Tutorial12 - function composition.csproj
├── Tutorial13_pure_functions
├── Box.cs
├── Program.cs
└── Tutorial13 - pure functions.csproj
├── Tutorial14_Intro_to_Eithers
├── Program.cs
└── Tutorial14 - Intro to Eithers.csproj
├── Tutorial15_BiBind
├── Program.cs
└── Tutorial15 - BiBind().csproj
├── Tutorial16_BiExists
├── Program.cs
└── Tutorial16 - BiExists().csproj
├── Tutorial17_Fold
├── Program.cs
└── Tutorial17 - Fold().csproj
├── Tutorial18_Iter
├── Program.cs
└── Tutorial18 - Iter().csproj
├── Tutorial19_BiMap
├── Program.cs
└── Tutorial19 - BiMap().csproj
├── Tutorial20_BindLeft
├── Program.cs
└── Tutorial20 - BindLeft().csproj
├── Tutorial21_Match
├── Program.cs
└── Tutorial21 Match().csproj
├── Tutorial22_BiMapT_and_MapT
├── Program.cs
└── Tutorial22 - BiMapT() and MapT().csproj
├── Tutorial23_BindT
├── Program.cs
└── Tutorial23 - BindT().csproj
├── Tutorial24_IterT
├── Program.cs
└── Tutorial24 - IterT().csproj
├── Tutorial25_Apply
├── Program.cs
└── Tutorial25 - Apply().csproj
├── Tutorial26_Partition
├── Program.cs
└── Tutorial26 - Partition().csproj
├── Tutorial27_Match
├── Program.cs
└── Tutorial27 - Match().csproj
├── Tutorial28_Intro_to_Option
├── Program.cs
└── Tutorial28 - Intro to Option.csproj
├── Tutorial29_Option_Basics
├── Program.cs
└── Tutorial29 - Option Basics.csproj
├── Tutorial30_Option_in_functions
├── Program.cs
└── Tutorial30 - Option in functions.csproj
├── Tutorial31_IfSome_and_IfNone
├── Program.cs
└── Tutorial31 - IfSome() and IfNone().csproj
├── Tutorial32_Pipelining_with_Optionsial32
├── Program.cs
└── Tutorial32 - Pipelining with Options.csproj
├── Tutorial33_ToEither
├── Program.cs
└── Tutorial33 - ToEither.csproj
├── Tutorial34_BiMap()
├── Program.cs
└── Tutorial34 - BiMap().csproj
├── Tutorial35_ThrowIfFailed()
├── CustomExtensions.cs
├── IAmFailure.cs
├── Program.cs
└── Tutorial35 - ThrowIfFailed().csproj
├── Tutorial36_FailureToNone
├── CustomExtensions.cs
├── IAmFailure.cs
├── Program.cs
└── Tutorial36 - FailureToNone.csproj
├── Tutorial37_Caching_and_Memoization
├── Program.cs
└── Tutorial37 - Caching and Memoization.csproj
├── Tutorial38_Changing_state_over_time
├── ChangeAgeEvent.cs
├── ChangeExpertiseEvent.cs
├── ChangeNameEvent.cs
├── ChangeRoleEvent.cs
├── Event.cs
├── Person.cs
├── Program.cs
└── Tutorial38 - Changing state over time.csproj
├── Tutorial39_Immutability_Smart_Constructors
├── Person.cs
├── PersonExtensions.cs
├── Program.cs
└── Tutorial39 - Immutability Smart Constructors.csproj
├── Tutorial40_Try
├── Extensions.cs
├── ExternalLibraryFailure.cs
├── IAmFailure.cs
├── Program.cs
└── Tutorial40 - Try.csproj
├── Tutorial41_Statics
├── Failures
│ ├── AggregatePipelineFailure.cs
│ ├── ConditionNotSatisfiedFailure.cs
│ ├── ExceptionFailure.cs
│ ├── ExternalLibraryFailure.cs
│ ├── IAmFailure.cs
│ ├── InvalidDataFailure.cs
│ ├── NotFound.cs
│ ├── NotTypeExceptionFailure.cs
│ ├── ShortCircuitFailure.cs
│ ├── TransformExceptionFailure.cs
│ ├── UnexpectedFailure.cs
│ ├── UnexpectedFailureException.cs
│ └── UninitializedFailure.cs
├── Program.cs
├── Statics.cs
└── Tutorial41 - Dealing with errors.csproj
├── UnderstandingLanguageExt.sln
├── UnderstandingLanguageExtTutorial.csproj
├── make.sh
├── myMediaFolder
└── media
│ ├── image10.png
│ ├── image101.png
│ ├── image103.png
│ ├── image105.png
│ ├── image107.png
│ ├── image109.png
│ ├── image111.png
│ ├── image113.png
│ ├── image115.png
│ ├── image117.png
│ ├── image119.png
│ ├── image12.png
│ ├── image121.png
│ ├── image123.png
│ ├── image125.png
│ ├── image127.png
│ ├── image14.png
│ ├── image15.png
│ ├── image17.png
│ ├── image18.png
│ ├── image2.png
│ ├── image20.png
│ ├── image23.png
│ ├── image25.png
│ ├── image27.png
│ ├── image29.png
│ ├── image31.png
│ ├── image33.png
│ ├── image35.png
│ ├── image37.png
│ ├── image39.png
│ ├── image4.png
│ ├── image41.png
│ ├── image43.png
│ ├── image45.png
│ ├── image48.png
│ ├── image49.png
│ ├── image51.png
│ ├── image53.png
│ ├── image55.png
│ ├── image57.png
│ ├── image59.png
│ ├── image6.png
│ ├── image61.png
│ ├── image63.png
│ ├── image65.png
│ ├── image67.png
│ ├── image69.png
│ ├── image71.png
│ ├── image73.png
│ ├── image75.png
│ ├── image77.png
│ ├── image79.png
│ ├── image8.png
│ ├── image81.png
│ ├── image83.png
│ ├── image85.png
│ ├── image87.png
│ ├── image89.png
│ ├── image91.png
│ ├── image93.png
│ ├── image95.png
│ ├── image97.png
│ └── image99.png
├── rename.bat
├── tutorial.md
└── tutorial1.md
/Applying_and_Evaluating_Functional_Programming_Paradigms_and_Techniques_in_Developing_Games.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stumathews/UnderstandingLanguageExt/2ddff3f4773665c9805d1d8ae2fa12741a16ff0e/Applying_and_Evaluating_Functional_Programming_Paradigms_and_Techniques_in_Developing_Games.pdf
--------------------------------------------------------------------------------
/PracticalLanguageExt.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stumathews/UnderstandingLanguageExt/2ddff3f4773665c9805d1d8ae2fa12741a16ff0e/PracticalLanguageExt.pdf
--------------------------------------------------------------------------------
/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace LanguageExtForNewDevelopersTutorial
4 | {
5 | class Program
6 | {
7 | static void Main(string[] args)
8 | {
9 | return;
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/The Language Ext Tutorial.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stumathews/UnderstandingLanguageExt/2ddff3f4773665c9805d1d8ae2fa12741a16ff0e/The Language Ext Tutorial.pdf
--------------------------------------------------------------------------------
/Tutorial01_monad/Box.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.Runtime.InteropServices.ComTypes;
5 |
6 | namespace Tutorial01
7 | {
8 | ///
9 | /// A box can hold a thing only
10 | ///
11 | /// The type of the thing
12 | public class Box
13 | {
14 | public Box(T newItem)
15 | {
16 | Item = newItem;
17 | IsEmpty = false;
18 | }
19 |
20 | public Box() { }
21 |
22 | private T _item;
23 |
24 | public T Item
25 | {
26 | get => _item;
27 | set
28 | {
29 | _item = value;
30 | IsEmpty = false;
31 | }
32 | }
33 |
34 | public bool IsEmpty = true;
35 | }
36 |
37 | public static class BoxMethods
38 | {
39 | ///
40 | /// Transforms the contents of a Box, in a user defined way
41 | ///
42 | /// The type of the thing in the box to start with
43 | /// The result type that the transforming function to transform to
44 | /// The Box that the extension method will work on
45 | /// User defined way to transform the contents of the box
46 | /// The results of the transformation, put back into a box
47 | public static Box Select(this Box box, Func map)
48 | {
49 | // Validate/Check if box is valid(not empty) and if so, run the transformation function on it, otherwise don't
50 | if (box.IsEmpty)
51 | {
52 | // No, return the empty box
53 | return new Box();
54 | }
55 |
56 | // Extract the item from the Box and run the provided transform function ie run the map() function
57 | // ie map is the name of the transformation function the user provided.
58 | TB transformedItem = map(box.Item);
59 |
60 | return new Box(transformedItem);
61 | }
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/Tutorial01_monad/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Tutorial01
4 | {
5 | class Program
6 | {
7 | static void Main(string[] args)
8 | {
9 | // A Box, can hold any type but in this case it holds and makes provision for an int.
10 | // Look at the implementation of the Box, notice its just a C# Class I've created.
11 | Box myNumberBox1 = new Box(1);
12 |
13 | // I can look into the Box
14 | Console.WriteLine($"The contents of my NumberBox is initially is '{myNumberBox1.Item}'");
15 |
16 | // But this Box is different. It can be used in a Linq Expression.
17 | // This is because it has a special function defined for it called Select().
18 | // Have a look at Box class again, check out the Select() extension method at the bottom.
19 | // This single function allows the following Linq usages:
20 |
21 | // Fetch or Select() a value from the box by using the Box's Select() function implicitly
22 | var result = from number1 in myNumberBox1
23 | select number1 + 1; // This is called the 'Linq Expression Syntax' and requires Box to have a Select() function for it to work
24 |
25 | // This is called the Linq Fluent syntax - does the same thing as the above
26 | Box result2 = myNumberBox1.Select(x => x + 1); // x=> x+1 is the transformation function also known as a mapping function
27 |
28 | // Have a Look at Box class again, and specifically the Select() extension method again and try and understand what its doing.
29 | // Hint: Its doing two things 1) allowing you to pass a function to it that it will run for the item in the box 2) only doing 1) if
30 | // the contents of the box is valid (so it does some validation)
31 |
32 | Console.WriteLine($"The number is now after having passed a mapping function1 to it results in its contents being '{result.Item}'");
33 | Console.WriteLine($"The number is now after having passed a mapping function2 to it results in its contents being '{result2.Item}'");
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/Tutorial01_monad/Tutorial01 - Monad.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | Exe
4 | netcoreapp3.1
5 | 40
6 | C:\Users\Stuart\git\LanguageExtForNewDevelopers\Backup\Tutorial0 - monad
7 | 2.0
8 |
9 |
--------------------------------------------------------------------------------
/Tutorial02_transformations_1/Box.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.Reflection.PortableExecutable;
5 | using System.Runtime.InteropServices.ComTypes;
6 | using System.Threading.Tasks.Dataflow;
7 |
8 | namespace Tutorial01
9 | {
10 | ///
11 | /// A box can hold 1 thing only
12 | ///
13 | /// The type of the thing
14 | public class Box
15 | {
16 | public Box(T newItem)
17 | {
18 | Item = newItem;
19 | IsEmpty = false;
20 | }
21 |
22 | public Box() { }
23 |
24 | private T _item;
25 |
26 | public T Item
27 | {
28 | get => _item;
29 | set
30 | {
31 | _item = value;
32 | IsEmpty = false;
33 | }
34 | }
35 |
36 | public bool IsEmpty = true;
37 |
38 |
39 | }
40 |
41 | public static class BoxMethods
42 | {
43 | ///
44 | /// Validate, Extract, Transform and Lift (If Valid)
45 | ///
46 | public static Box Select(this Box box, Func map)
47 | {
48 | // Validate
49 | if (box.IsEmpty)
50 | return new Box();
51 |
52 | // Extract
53 | var extracted = box.Item;
54 |
55 | // Transform
56 | TB transformedItem = map(extracted);
57 |
58 | // Lift
59 | return new Box(transformedItem);
60 | }
61 |
62 | ///
63 | /// Validate, Extract, Transform and Lift (If Valid)
64 | /// Check/Validate then transform to T and lift into Box
65 | ///
66 | public static Box Bind(this Box box, Func> bind /*liftAndTransform*/)
67 | {
68 | // Validate
69 | if(box.IsEmpty)
70 | return new Box();
71 |
72 | //Extract
73 | TA extract = box.Item;
74 |
75 | // Transform and the user-defined function (notice that its up to the user defined function to 'lift' any result of the transformation into a new Box)
76 | Box transformedAndLifted = bind(extract); // should return its results of its transformation in a Box
77 |
78 | return transformedAndLifted;
79 | }
80 |
81 | ///
82 | /// Validate, Extract, Transform and automatic Lift (If Valid)
83 | ///
84 | public static Box Map(this Box box, Func select /*Transform*/)
85 | {
86 | // Validate
87 | if(box.IsEmpty)
88 | return new Box();
89 |
90 | // Extract
91 | TA extract = box.Item;
92 |
93 | // Transform
94 | TB transformed = select(extract); // user provided function does not need to 'lift' its result into a Box like Bind() requires
95 |
96 | // Lift
97 | return new Box(transformed);
98 | }
99 | }
100 |
101 | }
102 |
--------------------------------------------------------------------------------
/Tutorial02_transformations_1/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Tutorial01;
3 |
4 | namespace Tutorial02
5 | {
6 | class Program
7 | {
8 | static void Main(string[] args)
9 | {
10 | // Now my Box contains another kind of thing, a list of integers. So effectively my Box is a box of numbers!
11 | Box numbers1 = new Box(new []{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10});
12 | Box numbers2 = new Box(new[] { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 });
13 |
14 | // Now have a look at Box class again, it has changed a little with two new extension methods.
15 |
16 | // Notice how the it (the extension methods) follows an interesting trend of doing VETL or Validate content, Extract Content, Transform Content and Lift the content
17 |
18 | // Validate, Extract, Transform and YouLift(If Valid)
19 | Box transformedResult1 = numbers1.Bind(contents => MyFunction(contents)); // user define transformation passed to bind(), this currently just ignores the extracted contents in the Box and returns a new set of numbers as dictated by MyFunction()
20 |
21 | // Validate, Extract, Transform and automatic Lift (If Valid)
22 | Box transformedResult2 = numbers2.Map(contents => MyFunction2(contents)); // same transformation result, but we our transformation function didn't
23 | // have to return a Box (we used map to run our transformation which automatically will put the result of our transform function in a new Box)
24 |
25 | // The Box class is now considered a Monad, because it has these two additional functions defined on it (map and bind).
26 | // Note in both cases of Bind() and Map() we did a transformation of the contents ie we provided a function that would work on the item in the Box(or Monad)
27 |
28 | // In both cases we didn't doing anything with the contents of the box, so we didn't really transform the contents(we just used what Map() and Bind() extracted from the box)
29 | // We could have included the contents in our transformation and manipulated it...
30 |
31 | // The take away is that Map() and Bind() do the same thing but Bind() requires you to put your transformation result back in the Box, while Map doesn't.
32 | // Both methods 'manage' your user defined transform function by running it only if it deems it should (validation passes) and then depending on the specific function,
33 | // it will either lisft the result of the transformation(map) or require that your transformation function's signature explicitly says it will it it itself (bind)
34 |
35 | // This means, with a you dont have to return a Box (like you do when you with Bind), when transforming with the Map() function...it automatically does this for you
36 |
37 | Console.WriteLine($"The result of the Bind operation was {transformedResult1.Item}");
38 | Console.WriteLine($"The result of the Map operation was {transformedResult2.Item}");
39 |
40 | // But here is something sneaky:
41 | Box transformedResult3 = numbers1.Map(contents => "I'm a string!"); // Look, we've been able to change the type of the Box from a int[] to a string!
42 | // This is by virtue of the fact that its what your transformation function returned, and it transformed the return type also...and put it back into a box
43 | // Its still in a Box, but is a box of a string now instead of a box of numbers.... Map() and Bind() can do this, and this is what makes these function really at transformations
44 | }
45 |
46 | private static int[] MyFunction2(int[] numbers)
47 | {
48 | // Used as a map() transformation, so no need to lift into a Box or anything...
49 | return new int[] {3, 4, 5};
50 | }
51 |
52 | private static Box MyFunction(int[] integerArray)
53 | {
54 | // Notice that this function if its going to be used in Box's Bind() function (and is indeed compatible with it - see Bind function signature), needs to return a new Box ie lift into a Box() again
55 | return new Box(new int[] {1, 2});
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/Tutorial02_transformations_1/Tutorial02 - Transformations 1.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | Exe
4 | netcoreapp3.1
5 | 40
6 | C:\Users\Stuart\git\LanguageExtForNewDevelopers\Backup\Tutorial02\
7 | 2.0
8 |
9 |
--------------------------------------------------------------------------------
/Tutorial03_pipelines/Box.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.Reflection.PortableExecutable;
5 | using System.Runtime.InteropServices.ComTypes;
6 | using System.Threading.Tasks.Dataflow;
7 |
8 | // This box has not changed its meaning since the last tutorial
9 | namespace Tutorial01
10 | {
11 | ///
12 | /// A box can hold 1 thing only
13 | ///
14 | /// The type of the thing
15 | public class Box
16 | {
17 | public Box(T newItem)
18 | {
19 | Item = newItem;
20 | IsEmpty = false;
21 | }
22 |
23 | public Box() { }
24 |
25 | private T _item;
26 |
27 | public T Item
28 | {
29 | get => _item;
30 | set
31 | {
32 | _item = value;
33 | IsEmpty = false;
34 | }
35 | }
36 |
37 | public bool IsEmpty = true;
38 |
39 |
40 | }
41 |
42 | public static class BoxMethods
43 | {
44 | ///
45 | /// Validate, Extract, Transform and Lift (If Valid)
46 | ///
47 | public static Box Select(this Box box, Func map)
48 | {
49 | // Validate
50 | if (box.IsEmpty)
51 | return new Box();
52 |
53 | // Extract
54 | var extracted = box.Item;
55 |
56 | // Transform
57 | TB transformedItem = map(extracted);
58 |
59 | // Lift
60 | return new Box(transformedItem);
61 | }
62 |
63 | ///
64 | /// Validate, Extract, Transform and Lift (If Valid)
65 | /// Check/Validate then transform to T and lift into Box
66 | ///
67 | public static Box Bind(this Box box, Func> bind /*liftAndTransform*/)
68 | {
69 | // Validate
70 | if(box.IsEmpty)
71 | return new Box();
72 |
73 | //Extract
74 | TA extract = box.Item;
75 |
76 | // Transform and lift
77 | Box transformedAndLifted = bind(extract);
78 |
79 | return transformedAndLifted;
80 | }
81 |
82 | ///
83 | /// Validate, Extract, Transform and automatic Lift (If Valid)
84 | ///
85 | public static Box Map(this Box box, Func select /*Transform*/)
86 | {
87 | // Validate
88 | if(box.IsEmpty)
89 | return new Box();
90 |
91 | // Extract
92 | TA extract = box.Item;
93 |
94 | // Transform
95 | TB transformed = select(extract);
96 |
97 | // Lift
98 | return new Box(transformed);
99 | }
100 | }
101 |
102 | }
103 |
--------------------------------------------------------------------------------
/Tutorial03_pipelines/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Tutorial01;
3 |
4 | namespace Tutorial03
5 | {
6 | // We continue working on our Monad type, Box.
7 | // Showing how short-circuiting works when chaining or cascading multiple Bind() or Map() operations
8 | class Program
9 | {
10 | static void Main(string[] args)
11 | {
12 | // Before working further on out Monad Box, read this :
13 | // Why do we actually need Monads? Why do we have to have Map() and Bind()
14 | // Here is why? https://stackoverflow.com/questions/28139259/why-do-we-need-monads
15 |
16 | Box numberHolder = new Box(25);
17 | Box stringHolder = new Box("Twenty Five");
18 |
19 | //Validate, Extract, Transform, lift
20 | Box result1 = numberHolder.Map(i => "Dude Ive Been Transformed To a string automatically");
21 |
22 | // Transform the contents of the box by passing it down a series of Bind()s
23 | // so there are multiple associated VETL->VETL->VETL steps that represents the Binds()
24 | // effectively representing a pipeline of data going in and out of Bind(VETL) functions
25 | Box result2 = stringHolder
26 | .Bind(s => new Box(2)) //Validate Extract Transform lift
27 | .Bind(i => new Box()) // Validate step only
28 | .Bind(i => new Box("hello")); // Validate step only
29 |
30 | // Remember that the 'validate' step is implicit and is actually coded directly into the Bind() or Map() functions.
31 | // The validity of a box in this case, is if it is empty or not(look at the Bind functions' code that explicitly checks this),
32 | // It is empty(invalid) it will not run the the user provided transformation function, otherwise it will.
33 |
34 | // This is an example of 'short-circuiting' out-of the
35 | // entire set of transformations early. So if the First Bind short-circuits, the next Binds will too and so they will not run
36 |
37 | Console.WriteLine($"The contents of result 2 is {result2.Item}");
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/Tutorial03_pipelines/Tutorial03 - Pipelines.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | Exe
4 | netcoreapp3.1
5 | 40
6 | C:\Users\Stuart\git\LanguageExtForNewDevelopers\Backup\Tutorial03\
7 | 2.0
8 |
9 |
--------------------------------------------------------------------------------
/Tutorial04_methods_1/Box.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.Reflection.PortableExecutable;
5 | using System.Runtime.InteropServices.ComTypes;
6 | using System.Threading.Tasks.Dataflow;
7 |
8 | namespace Tutorial01
9 | {
10 | ///
11 | /// A box can hold 1 thing only
12 | ///
13 | /// The type of the thing
14 | public class Box
15 | {
16 | public Box(T newItem)
17 | {
18 | Item = newItem;
19 | IsEmpty = false;
20 | }
21 |
22 | public Box() { }
23 |
24 | private T _item;
25 |
26 | public T Item
27 | {
28 | get => _item;
29 | set
30 | {
31 | _item = value;
32 | IsEmpty = false;
33 | }
34 | }
35 |
36 | public bool IsEmpty = true;
37 |
38 |
39 | }
40 |
41 | public static class BoxMethods
42 | {
43 | ///
44 | /// Validate, Extract, Transform and Lift (If Valid)
45 | ///
46 | public static Box Select(this Box box, Func map)
47 | {
48 | // Validate
49 | if (box.IsEmpty)
50 | return new Box();
51 |
52 | // Extract
53 | var extracted = box.Item;
54 |
55 | // Transform
56 | TB transformedItem = map(extracted);
57 |
58 | // Lift
59 | return new Box(transformedItem);
60 | }
61 |
62 | ///
63 | /// Validate, Extract, Transform, Project(Transform, Extract) and automatic Lift
64 | ///
65 | public static Box SelectMany(this Box box, Func> bind /*liftTo*/, Func project)
66 | {
67 | // Validate
68 | if(box.IsEmpty)
69 | return new Box();
70 |
71 | // Extract
72 | var extract = box.Item;
73 |
74 | // Transform and LiftTo
75 | Box liftedResult = bind(extract);
76 |
77 | if(liftedResult.IsEmpty)
78 | return new Box();
79 |
80 | // Project/Combine
81 | TC t2 = project(extract, liftedResult.Item); // This forms the select xzy in the Linq Expression in the tutorial.
82 | return new Box(t2);
83 | }
84 |
85 | ///
86 | /// Validate, Extract, Transform and Lift (If Valid)
87 | /// Check/Validate then transform to T and lift into Box
88 | ///
89 | public static Box Bind(this Box box, Func> bind /*liftAndTransform*/)
90 | {
91 | // Validate
92 | if(box.IsEmpty)
93 | return new Box();
94 |
95 | //Extract
96 | TA extract = box.Item;
97 |
98 | // Transform and lift
99 | Box transformedAndLifted = bind(extract);
100 |
101 | return transformedAndLifted;
102 | }
103 |
104 | ///
105 | /// Validate, Extract, Transform and automatic Lift (If Valid)
106 | ///
107 | public static Box Map(this Box box, Func select /*Transform*/)
108 | {
109 | // Validate
110 | if(box.IsEmpty)
111 | return new Box();
112 |
113 | // Extract
114 | TA extract = box.Item;
115 |
116 | // Transform
117 | TB transformed = select(extract);
118 |
119 | // Lift
120 | return new Box(transformed);
121 | }
122 | }
123 |
124 | }
125 |
--------------------------------------------------------------------------------
/Tutorial04_methods_1/Tutorial04 - Methods 1.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | Exe
4 | netcoreapp3.1
5 | 40
6 | C:\Users\Stuart\git\LanguageExtForNewDevelopers\Backup\Tutorial04\
7 | 2.0
8 |
9 |
--------------------------------------------------------------------------------
/Tutorial05_methods_2/Box.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.Reflection.PortableExecutable;
5 | using System.Runtime.InteropServices.ComTypes;
6 | using System.Threading.Tasks.Dataflow;
7 |
8 | // Box has not changed since last tutorial
9 | namespace Tutorial05
10 | {
11 | ///
12 | /// A box can hold 1 thing only
13 | ///
14 | /// The type of the thing
15 | public class Box
16 | {
17 | public Box(T newExtract)
18 | {
19 | Extract = newExtract;
20 | IsEmpty = false;
21 | }
22 |
23 | public Box() { }
24 |
25 | private T _extract;
26 |
27 | public T Extract
28 | {
29 | get => _extract;
30 | set
31 | {
32 | _extract = value;
33 | IsEmpty = false;
34 | }
35 | }
36 |
37 | public bool IsEmpty = true;
38 |
39 |
40 | }
41 |
42 | public static class BoxMethods
43 | {
44 | ///
45 | /// Validate, Extract, Transform and Lift (If Valid)
46 | ///
47 | public static Box Select(this Box box, Func map)
48 | {
49 | // Validate
50 | if (box.IsEmpty)
51 | return new Box();
52 |
53 | // Extract
54 | var extracted = box.Extract;
55 |
56 | // Transform
57 | TB transformedItem = map(extracted);
58 |
59 | // Lift
60 | return new Box(transformedItem);
61 | }
62 |
63 | ///
64 | /// Validate, Extract, Transform, Project(Transform, Extract) and automatic Lift
65 | ///
66 |
67 | public static Box SelectMany(this Box box, Func> bind /*liftTo*/, Func project)
68 | {
69 | // Validate
70 | if(box.IsEmpty)
71 | return new Box();
72 |
73 | // Extract
74 | var extract = box.Extract;
75 |
76 | // Transform and LiftTo
77 | Box liftedResult = bind(extract);
78 |
79 | // Project/Combine
80 | TC t2 = project(extract, liftedResult.Extract);
81 | return new Box(t2);
82 | }
83 |
84 | ///
85 | /// Validate, Extract, Transform and Lift (If Valid)
86 | /// Check/Validate then transform to T and lift into Box
87 | ///
88 | public static Box Bind(this Box box, Func> bind /*liftAndTransform*/)
89 | {
90 | // Validate
91 | if(box.IsEmpty)
92 | return new Box();
93 |
94 | //Extract
95 | TA extract = box.Extract;
96 |
97 | // Transform and lift
98 | Box transformedAndLifted = bind(extract);
99 |
100 | return transformedAndLifted;
101 | }
102 |
103 | ///
104 | /// Validate, Extract, Transform and automatic Lift (If Valid)
105 | ///
106 | public static Box Map(this Box box, Func select /*Transform*/)
107 | {
108 | // Validate
109 | if(box.IsEmpty)
110 | return new Box();
111 |
112 | // Extract
113 | TA extract = box.Extract;
114 |
115 | // Transform
116 | TB transformed = select(extract);
117 |
118 | // Lift
119 | return new Box(transformed);
120 | }
121 | }
122 |
123 | }
124 |
--------------------------------------------------------------------------------
/Tutorial05_methods_2/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using Tutorial05;
4 | // Shows various invocations of Bind() and Map() using lambda functions as the user defined transform functions, explicit named functions, and
5 | // using both linq query syntax and fluent forms.
6 | namespace Tutorial05
7 | {
8 | class Program
9 | {
10 | static void Main(string[] args)
11 | {
12 | // A Box
13 | Box boxOfIntegers = new Box(new[] { 3, 5, 7, 9, 11, 13, 15 });
14 | Box boxOfNewIntegers = new Box(new[] { 3, 5, 88, 29, 155, 123, 1 });
15 |
16 | // Do something with or to the Box, uses user defined function specified in the form of lambdas to the Map() and Bind() functions
17 |
18 | var doubled1 = boxOfIntegers
19 | .Bind(extract => new Box(extract.Select(x => x * 2).ToArray())); // Extract, Validate and transform using Bind()
20 |
21 | var doubled2 = boxOfIntegers
22 | .Map(numbers => numbers.Select(x => x * 2).ToArray()); // Extract, Validate and transform using Bind()
23 |
24 | // Extract, Validate and transform using SelectMany()
25 | var doubled3 = from extract in boxOfIntegers
26 | from transformed in DoubleNumbers(extract) // bind() part of SelectMany() ie transform extracted value
27 | select transformed; // project(extract, transformedAndLiftedResult) part of SelectMany
28 |
29 | var doubled4 = from extract in boxOfIntegers
30 | select DoubleNumbers(extract).Extract; // Use Select via linq expression syntax
31 |
32 | // Note we can use Map or Bind for transformation, but it becomes necessary to choose/use a specific one depending
33 | // on if or not the provided transformation function returns a box or not (lifts or doesn't),
34 | // ie is transformed in a call to Bind() or Map()
35 | Box doubleDouble1 = boxOfIntegers
36 | .Bind(numbers => DoubleNumbers(numbers)) // need to use a transformation function that will lift
37 | .Map(DoubleNumbers) // need to use a transformation that does not already lift
38 | .Bind(box => box.Bind( numbers => DoubleNumbers(numbers) )); // same as above bind() case
39 |
40 | // Using Linq query syntax
41 | var doubleDouble2 = from numbers in boxOfIntegers
42 | from redoubled in DoubleNumbers(numbers) // transformation function needs to lift
43 | select redoubled; // Box's Select() function will do the lift here into Box so no need to in this line
44 |
45 |
46 | // Give me a box of Double Double of my Box
47 | var doubleDouble3 = from firstDoubleTransformation in DoubleMyBox(boxOfIntegers)
48 | from secondDoubleTransformation in DoubleNumbers(firstDoubleTransformation) //VET: bind part of SelectMany()
49 | select secondDoubleTransformation; // project(reDouble, firstDouble)
50 | }
51 |
52 | ///
53 | /// Takes a Box of numbers and produces a box of doubled numbers
54 | ///
55 | private static Box DoubleMyBox(Box boxOfIntegers)
56 | {
57 | return from extract in boxOfIntegers
58 | from doubledNumber in DoubleNumbers(extract)
59 | select doubledNumber;
60 | }
61 |
62 | // transform Extracted, and Lift it
63 | static Box DoubleNumbers(int[] extract)
64 | {
65 | return new Box(extract.Select(x => x * 2).ToArray());
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/Tutorial05_methods_2/Tutorial05 - Methods 2.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | Exe
4 | netcoreapp3.1
5 | 40
6 | C:\Users\Stuart\git\LanguageExtForNewDevelopers\Backup\Tutorial05\
7 | 2.0
8 |
9 |
--------------------------------------------------------------------------------
/Tutorial06_Linq/Box.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.Reflection.PortableExecutable;
5 | using System.Runtime.InteropServices.ComTypes;
6 | using System.Threading.Tasks.Dataflow;
7 |
8 | namespace Tutorial06
9 | {
10 | ///
11 | /// A box can hold 1 thing only
12 | ///
13 | /// The type of the thing
14 | public class Box
15 | {
16 | public Box(T newExtract)
17 | {
18 | Extract = newExtract;
19 | IsEmpty = false;
20 | }
21 |
22 | public Box() { }
23 |
24 | private T _extract;
25 |
26 | public T Extract
27 | {
28 | get => _extract;
29 | set
30 | {
31 | _extract = value;
32 | IsEmpty = false;
33 | }
34 | }
35 |
36 | public bool IsEmpty = true;
37 |
38 |
39 | }
40 |
41 | public static class BoxMethods
42 | {
43 | ///
44 | /// Validate, Extract, Transform and Lift (If Valid)
45 | ///
46 | public static Box Select(this Box box, Func map)
47 | {
48 | // Validate
49 | if (box.IsEmpty)
50 | return new Box();
51 |
52 | // Extract
53 | var extracted = box.Extract;
54 |
55 | // Transform
56 | TB transformedItem = map(extracted);
57 |
58 | // Lift
59 | return new Box(transformedItem);
60 | }
61 |
62 | ///
63 | /// Validate, Extract, Transform, Project(Transform, Extract) and automatic Lift
64 | ///
65 |
66 | public static Box SelectMany(this Box box, Func> bind /*liftTo*/, Func project) //Notice that the transformation function in SelectMany() is actually called bind()
67 | {
68 | // Validate
69 | if(box.IsEmpty)
70 | return new Box();
71 |
72 | // Extract
73 | var extract = box.Extract;
74 |
75 | // Transform and LiftTo
76 | Box liftedResult = bind(extract);
77 |
78 | if(liftedResult.IsEmpty)
79 | return new Box();
80 |
81 | // Project/Combine
82 | TC t2 = project(extract, liftedResult.Extract);
83 | return new Box(t2);
84 | }
85 |
86 | ///
87 | /// Validate, Extract, Transform and Lift (If Valid)
88 | /// Check/Validate then transform to T and lift into Box
89 | ///
90 | public static Box Bind(this Box box, Func> bind /*liftAndTransform*/)
91 | {
92 | // Validate
93 | if(box.IsEmpty)
94 | return new Box();
95 |
96 | //Extract
97 | TA extract = box.Extract;
98 |
99 | // Transform and lift
100 | Box transformedAndLifted = bind(extract);
101 |
102 | return transformedAndLifted;
103 | }
104 |
105 | ///
106 | /// Validate, Extract, Transform and automatic Lift (If Valid)
107 | ///
108 | public static Box Map(this Box box, Func select /*Transform*/)
109 | {
110 | // Validate
111 | if(box.IsEmpty)
112 | return new Box();
113 |
114 | // Extract
115 | TA extract = box.Extract;
116 |
117 | // Transform
118 | TB transformed = select(extract);
119 |
120 | // Lift
121 | return new Box(transformed);
122 | }
123 | }
124 |
125 | }
126 |
--------------------------------------------------------------------------------
/Tutorial06_Linq/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 |
4 | /*
5 | This tutorial shows you how pipelining/chaining/cascading is used to call functions.
6 | This tutorial shows how to use the Linq Fluent and Expression syntax to achieve the same thing
7 | This also demonstrates what is a Perfect or valid map and bind function and show when to use map and bind and why
8 | */
9 | namespace Tutorial06
10 | {
11 | class Program
12 | {
13 | static void Main(string[] args)
14 | {
15 | // A Box
16 | Box boxOfIntegers = new Box(new[] { 3, 5, 7, 9, 11, 13, 15 });
17 | Box boxOfNewIntegers = new Box(new[] { 3, 5, 88, 29, 155, 123, 1 });
18 |
19 | // Do something with or to the Box
20 |
21 | /* Shown: Using the select many way, ie the linq expression syntax as shown below allows an extracted item from the box, then to be
22 | * passed down a series of transforms by way of those transform functions being compatible with the bind() phase of the SelectMany() function.
23 |
24 | Each can see the prior transformation and can act on it subsequently.
25 |
26 | And as each transformation function is run as part of the SelectMany() implementation of Box, it will also be subject to the VETL phases
27 | which means if the input is not valid, it will return a invalid value and subsequent transforms upon receiving that invalid input will also
28 | return an invalid input and in all those cases i doing that the underlying transform is not run (short-circuiting).
29 | */
30 | Box