├── .gitignore ├── ChurchEncoding.sln ├── ChurchEncoding ├── BinaryTree.cs ├── BinaryTreeTests.cs ├── BooleanTests.cs ├── ChurchAnd.cs ├── ChurchBoolean.cs ├── ChurchBooleanVisitor.cs ├── ChurchEncoding.csproj ├── ChurchFalse.cs ├── ChurchNot.cs ├── ChurchOr.cs ├── ChurchTrue.cs ├── Either.cs ├── EitherTests.cs ├── FromMaybeVisitor.cs ├── IBinaryTree.cs ├── IChurchBoolean.cs ├── IEither.cs ├── IEitherVisitor.cs ├── IMaybe.cs ├── IMaybeVisitor.cs ├── INaturalNumber.cs ├── INaturalNumberVisitor.cs ├── IRoseTree.cs ├── IRoseTreeVisitor.cs ├── Just.cs ├── Leaf.cs ├── Left.cs ├── Maybe.cs ├── MaybeTests.cs ├── NatualNumberTests.cs ├── NaturalNumber.cs ├── Node.cs ├── Nothing.cs ├── PaymentExample │ ├── Child.cs │ ├── ChildPaymentService.cs │ ├── IPaymentType.cs │ ├── IPaymentTypeVisitor.cs │ ├── Individual.cs │ ├── Parent.cs │ ├── PaymentJsonModel.cs │ ├── PaymentService.cs │ ├── PaymentType.cs │ └── PaymentTypeTests.cs ├── Properties │ └── AssemblyInfo.cs ├── Right.cs ├── RoseLeaf.cs ├── RoseNode.cs ├── RoseTree.cs ├── RoseTreeTests.cs ├── Successor.cs ├── Zero.cs └── packages.config ├── LICENSE ├── README.md └── packages ├── xunit.2.3.1 └── xunit.2.3.1.nupkg ├── xunit.abstractions.2.0.1 ├── lib │ ├── net35 │ │ ├── xunit.abstractions.dll │ │ └── xunit.abstractions.xml │ └── netstandard1.0 │ │ ├── xunit.abstractions.dll │ │ └── xunit.abstractions.xml └── xunit.abstractions.2.0.1.nupkg ├── xunit.analyzers.0.7.0 ├── analyzers │ └── dotnet │ │ └── cs │ │ └── xunit.analyzers.dll ├── tools │ ├── install.ps1 │ └── uninstall.ps1 └── xunit.analyzers.0.7.0.nupkg ├── xunit.assert.2.3.1 ├── lib │ └── netstandard1.1 │ │ ├── xunit.assert.dll │ │ └── xunit.assert.xml └── xunit.assert.2.3.1.nupkg ├── xunit.core.2.3.1 ├── build │ ├── xunit.core.props │ ├── xunit.core.targets │ └── xunit.execution.desktop.dll ├── buildMultiTargeting │ ├── xunit.core.props │ └── xunit.core.targets └── xunit.core.2.3.1.nupkg ├── xunit.extensibility.core.2.3.1 ├── lib │ └── netstandard1.1 │ │ ├── xunit.core.dll │ │ ├── xunit.core.dll.tdnet │ │ ├── xunit.core.xml │ │ ├── xunit.runner.tdnet.dll │ │ └── xunit.runner.utility.net452.dll └── xunit.extensibility.core.2.3.1.nupkg └── xunit.extensibility.execution.2.3.1 ├── lib ├── net452 │ ├── xunit.execution.desktop.dll │ └── xunit.execution.desktop.xml └── netstandard1.1 │ ├── xunit.execution.dotnet.dll │ └── xunit.execution.dotnet.xml └── xunit.extensibility.execution.2.3.1.nupkg /.gitignore: -------------------------------------------------------------------------------- 1 | # Build Folders (you can keep bin if you'd like, to store dlls and pdbs) 2 | [Bb]in/ 3 | [Oo]bj/ 4 | 5 | # MsTest test results 6 | TestResults 7 | 8 | ## Ignore Visual Studio temporary files, build results, and 9 | ## files generated by popular Visual Studio add-ons. 10 | 11 | # User-specific files 12 | *.suo 13 | *.user 14 | *.sln.docstates 15 | .vs/ 16 | 17 | # Build results 18 | [Dd]ebug/ 19 | [Rr]elease/ 20 | x64/ 21 | *_i.c 22 | *_p.c 23 | *.ilk 24 | *.meta 25 | *.obj 26 | *.pch 27 | *.pgc 28 | *.pgd 29 | *.rsp 30 | *.sbr 31 | *.tlb 32 | *.tli 33 | *.tlh 34 | *.tmp 35 | *.log 36 | *.vspscc 37 | *.vssscc 38 | .builds 39 | 40 | # Visual C++ cache files 41 | ipch/ 42 | *.aps 43 | *.ncb 44 | *.opensdf 45 | *.sdf 46 | 47 | # Visual Studio profiler 48 | *.psess 49 | *.vsp 50 | *.vspx 51 | 52 | # Guidance Automation Toolkit 53 | *.gpState 54 | 55 | # ReSharper is a .NET coding add-in 56 | _ReSharper* 57 | 58 | # NCrunch 59 | *.ncrunch* 60 | .*crunch*.local.xml 61 | 62 | # Installshield output folder 63 | [Ee]xpress 64 | 65 | # DocProject is a documentation generator add-in 66 | DocProject/buildhelp/ 67 | DocProject/Help/*.HxT 68 | DocProject/Help/*.HxC 69 | DocProject/Help/*.hhc 70 | DocProject/Help/*.hhk 71 | DocProject/Help/*.hhp 72 | DocProject/Help/Html2 73 | DocProject/Help/html 74 | 75 | # Click-Once directory 76 | publish 77 | 78 | # Publish Web Output 79 | *.Publish.xml 80 | 81 | # Windows Azure Build Output 82 | csx 83 | *.build.csdef 84 | 85 | # Windows Store app package directory 86 | AppPackages/ 87 | 88 | # Backup & report files from converting an old project file to a newer 89 | # Visual Studio version. Backup files are not needed, because we have git ;-) 90 | _Upgr/ 91 | Backup*/ 92 | UpgradeLog*.XML 93 | 94 | # FAKE hidden directory 95 | .fake/ 96 | -------------------------------------------------------------------------------- /ChurchEncoding.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27130.2010 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChurchEncoding", "ChurchEncoding\ChurchEncoding.csproj", "{26956FAC-018B-41EE-99AE-144BED6F157A}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {26956FAC-018B-41EE-99AE-144BED6F157A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {26956FAC-018B-41EE-99AE-144BED6F157A}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {26956FAC-018B-41EE-99AE-144BED6F157A}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {26956FAC-018B-41EE-99AE-144BED6F157A}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {6031CCE8-EC10-4F94-9868-B5D1F4276D3C} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /ChurchEncoding/BinaryTree.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ploeh.Samples.ChurchEncoding 8 | { 9 | public static class BinaryTree 10 | { 11 | public static IBinaryTree Leaf(T item) 12 | { 13 | return new Leaf(item); 14 | } 15 | 16 | public static IBinaryTree Create( 17 | IBinaryTree left, 18 | T item, 19 | IBinaryTree right) 20 | { 21 | return new Node(left, item, right); 22 | } 23 | 24 | public static IBinaryTree Select( 25 | this IBinaryTree tree, 26 | Func selector) 27 | { 28 | if (tree == null) 29 | throw new ArgumentNullException(nameof(tree)); 30 | if (selector == null) 31 | throw new ArgumentNullException(nameof(selector)); 32 | 33 | return tree.Match( 34 | node: (l, x, r) => Create(l, selector(x), r), 35 | leaf: x => Leaf(selector(x))); 36 | } 37 | 38 | public static int Sum(this IBinaryTree tree) 39 | { 40 | return tree.Match((l, x, r) => l + x + r, x => x); 41 | } 42 | 43 | public static int Max(this IBinaryTree tree) 44 | { 45 | return tree.Match((l, x, r) => Math.Max(Math.Max(l, r), x), x => x); 46 | } 47 | 48 | public static int CountLeaves(this IBinaryTree tree) 49 | { 50 | return tree.Match((l, _, r) => l + r, _ => 1); 51 | } 52 | 53 | public static int MeasureDepth(this IBinaryTree tree) 54 | { 55 | return tree.Match((l, _, r) => 1 + Math.Max(l, r), _ => 0); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /ChurchEncoding/BinaryTreeTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Xunit; 7 | 8 | namespace Ploeh.Samples.ChurchEncoding 9 | { 10 | public class BinaryTreeTests 11 | { 12 | [Fact] 13 | public void BasicBinaryTreeExample() 14 | { 15 | var source = 16 | BinaryTree.Create( 17 | BinaryTree.Create( 18 | BinaryTree.Leaf(0), 19 | 1337, 20 | BinaryTree.Leaf(-22)), 21 | 42, 22 | BinaryTree.Leaf(100)); 23 | 24 | IBinaryTree dest = source.Select(i => i.ToString()); 25 | 26 | Assert.Equal("42", dest.Match((_l, x, _r) => x, x => x)); 27 | } 28 | 29 | [Fact] 30 | public void BinaryTreeQuerySyntaxExample() 31 | { 32 | var source = 33 | BinaryTree.Create( 34 | BinaryTree.Create( 35 | BinaryTree.Leaf(0), 36 | 1337, 37 | BinaryTree.Leaf(-22)), 38 | 42, 39 | BinaryTree.Leaf(100)); 40 | 41 | IBinaryTree dest = from i in source 42 | select i.ToString(); 43 | 44 | Assert.Equal("42", dest.Match((_l, x, _r) => x, x => x)); 45 | } 46 | 47 | public static IEnumerable Trees 48 | { 49 | get 50 | { 51 | yield return new[] { BinaryTree.Leaf(0) }; 52 | yield return new[] { 53 | BinaryTree.Create( 54 | BinaryTree.Leaf(2), 55 | -3, 56 | BinaryTree.Leaf(99)) }; 57 | yield return new[] { 58 | BinaryTree.Create( 59 | BinaryTree.Create( 60 | BinaryTree.Leaf(0), 61 | 1337, 62 | BinaryTree.Leaf(-22)), 63 | 42, 64 | BinaryTree.Leaf(100)) }; 65 | yield return new[] { 66 | BinaryTree.Create( 67 | BinaryTree.Leaf(2), 68 | -927, 69 | BinaryTree.Create( 70 | BinaryTree.Leaf(88), 71 | 211, 72 | BinaryTree.Leaf(132))) }; 73 | yield return new[] { 74 | BinaryTree.Create( 75 | BinaryTree.Create( 76 | BinaryTree.Leaf(113), 77 | -336, 78 | BinaryTree.Leaf(-432)), 79 | 111, 80 | BinaryTree.Create( 81 | BinaryTree.Leaf(-32), 82 | 1299, 83 | BinaryTree.Leaf(773))) }; 84 | } 85 | } 86 | 87 | [Theory, MemberData(nameof(Trees))] 88 | public void FirstFunctorLaw(IBinaryTree tree) 89 | { 90 | Assert.Equal(tree, tree.Select(x => x)); 91 | } 92 | 93 | [Theory, MemberData(nameof(Trees))] 94 | public void SecondFunctorLaw(IBinaryTree tree) 95 | { 96 | string g(int i) => i.ToString(); 97 | bool f(string s) => s.Length % 2 == 0; 98 | 99 | Assert.Equal(tree.Select(g).Select(f), tree.Select(i => f(g(i)))); 100 | } 101 | 102 | [Fact] 103 | public void SumOfNodes() 104 | { 105 | var tree = 106 | BinaryTree.Create( 107 | BinaryTree.Create( 108 | BinaryTree.Leaf(42), 109 | 1337, 110 | BinaryTree.Create( 111 | BinaryTree.Leaf(2112), 112 | 5040, 113 | BinaryTree.Leaf(1984))), 114 | 2, 115 | BinaryTree.Leaf(90125)); 116 | var actual = tree.Sum(); 117 | Assert.Equal(100642, actual); 118 | } 119 | 120 | [Fact] 121 | public void MaxNodes() 122 | { 123 | var tree = 124 | BinaryTree.Create( 125 | BinaryTree.Create( 126 | BinaryTree.Leaf(42), 127 | 1337, 128 | BinaryTree.Create( 129 | BinaryTree.Leaf(2112), 130 | 5040, 131 | BinaryTree.Leaf(1984))), 132 | 2, 133 | BinaryTree.Leaf(90125)); 134 | var actual = tree.Max(); 135 | Assert.Equal(90125, actual); 136 | } 137 | 138 | [Fact] 139 | public void CountLeaves() 140 | { 141 | var tree = 142 | BinaryTree.Create( 143 | BinaryTree.Create( 144 | BinaryTree.Leaf(42), 145 | 1337, 146 | BinaryTree.Create( 147 | BinaryTree.Leaf(2112), 148 | 5040, 149 | BinaryTree.Leaf(1984))), 150 | 2, 151 | BinaryTree.Leaf(90125)); 152 | var actual = tree.CountLeaves(); 153 | Assert.Equal(4, actual); 154 | } 155 | 156 | [Fact] 157 | public void MeasureDepth() 158 | { 159 | var tree = 160 | BinaryTree.Create( 161 | BinaryTree.Create( 162 | BinaryTree.Leaf(42), 163 | 1337, 164 | BinaryTree.Create( 165 | BinaryTree.Leaf(2112), 166 | 5040, 167 | BinaryTree.Leaf(1984))), 168 | 2, 169 | BinaryTree.Leaf(90125)); 170 | var actual = tree.MeasureDepth(); 171 | Assert.Equal(3, actual); 172 | } 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /ChurchEncoding/BooleanTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Xunit; 7 | 8 | namespace Ploeh.Samples.ChurchEncoding 9 | { 10 | public class BooleanTests 11 | { 12 | [Fact] 13 | public void Example1() 14 | { 15 | var actual = new ChurchAnd(new ChurchTrue(), new ChurchFalse()); 16 | Assert.False(actual.ToBool()); 17 | } 18 | 19 | [Fact] 20 | public void Example2() 21 | { 22 | var actual = new ChurchAnd(new ChurchTrue(), new ChurchTrue()); 23 | Assert.True(actual.ToBool()); 24 | } 25 | 26 | [Fact] 27 | public void Example3() 28 | { 29 | var actual = 30 | new ChurchNot( 31 | new ChurchOr( 32 | new ChurchFalse(), 33 | new ChurchTrue())); 34 | Assert.False(actual.ToBool()); 35 | } 36 | 37 | [Fact] 38 | public void StringExample1() 39 | { 40 | var b = new ChurchOr(new ChurchTrue(), new ChurchFalse()); 41 | var actual = 42 | b.Accept(new ChurchBooleanVisitor("foo", "bar")); 43 | Assert.Equal("foo", actual); 44 | } 45 | 46 | [Fact] 47 | public void StringExample2() 48 | { 49 | var b = 50 | new ChurchOr( 51 | new ChurchFalse(), 52 | new ChurchNot( 53 | new ChurchTrue())); 54 | var actual = 55 | b.Accept(new ChurchBooleanVisitor("foo", "bar")); 56 | Assert.Equal("bar", actual); 57 | } 58 | 59 | [Fact] 60 | public void Int32Example1() 61 | { 62 | var b = new ChurchOr(new ChurchFalse(), new ChurchFalse()); 63 | var actual = b.Accept(new ChurchBooleanVisitor(42, 1337)); 64 | Assert.Equal(1337, actual); 65 | } 66 | 67 | [Fact] 68 | public void Int32Example2() 69 | { 70 | var b = 71 | new ChurchNot( 72 | new ChurchAnd( 73 | new ChurchTrue(), 74 | new ChurchFalse())); 75 | var actual = b.Accept(new ChurchBooleanVisitor(42, 1337)); 76 | Assert.Equal(42, actual); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /ChurchEncoding/ChurchAnd.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ploeh.Samples.ChurchEncoding 8 | { 9 | public class ChurchAnd : IChurchBoolean 10 | { 11 | private readonly IChurchBoolean x; 12 | private readonly IChurchBoolean y; 13 | 14 | public ChurchAnd(IChurchBoolean x, IChurchBoolean y) 15 | { 16 | this.x = x; 17 | this.y = y; 18 | } 19 | 20 | public T Accept(ChurchBooleanVisitor visitor) 21 | { 22 | return x.Accept( 23 | new ChurchBooleanVisitor( 24 | y.Accept(visitor), 25 | visitor.VisitFalse)); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /ChurchEncoding/ChurchBoolean.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ploeh.Samples.ChurchEncoding 8 | { 9 | public static class ChurchBoolean 10 | { 11 | public static bool ToBool(this IChurchBoolean b) 12 | { 13 | return b.Accept(new ChurchBooleanVisitor(true, false)); 14 | } 15 | 16 | public static IChurchBoolean ToChurchBoolean(this bool b) 17 | { 18 | if (b) 19 | return new ChurchTrue(); 20 | else 21 | return new ChurchFalse(); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /ChurchEncoding/ChurchBooleanVisitor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ploeh.Samples.ChurchEncoding 8 | { 9 | public class ChurchBooleanVisitor 10 | { 11 | public ChurchBooleanVisitor(T trueCase, T falseCase) 12 | { 13 | VisitTrue = trueCase; 14 | VisitFalse = falseCase; 15 | } 16 | 17 | public T VisitTrue { get; } 18 | public T VisitFalse { get; } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ChurchEncoding/ChurchEncoding.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | Debug 7 | AnyCPU 8 | {26956FAC-018B-41EE-99AE-144BED6F157A} 9 | Library 10 | Properties 11 | Ploeh.Samples.ChurchEncoding 12 | Ploeh.Samples.ChurchEncoding 13 | v4.6.1 14 | 512 15 | 16 | 17 | 18 | 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | 27 | 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | ..\packages\xunit.abstractions.2.0.1\lib\net35\xunit.abstractions.dll 46 | 47 | 48 | ..\packages\xunit.assert.2.3.1\lib\netstandard1.1\xunit.assert.dll 49 | 50 | 51 | ..\packages\xunit.extensibility.core.2.3.1\lib\netstandard1.1\xunit.core.dll 52 | 53 | 54 | ..\packages\xunit.extensibility.execution.2.3.1\lib\net452\xunit.execution.desktop.dll 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 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 122 | 123 | 124 | 125 | 126 | 127 | 128 | -------------------------------------------------------------------------------- /ChurchEncoding/ChurchFalse.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ploeh.Samples.ChurchEncoding 8 | { 9 | public class ChurchFalse : IChurchBoolean 10 | { 11 | public T Accept(ChurchBooleanVisitor visitor) 12 | { 13 | return visitor.VisitFalse; 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /ChurchEncoding/ChurchNot.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Ploeh.Samples.ChurchEncoding 9 | { 10 | [DebuggerDisplay("{ b }")] 11 | public class ChurchNot : IChurchBoolean 12 | { 13 | private readonly IChurchBoolean b; 14 | 15 | public ChurchNot(IChurchBoolean b) 16 | { 17 | this.b = b; 18 | } 19 | 20 | public T Accept(ChurchBooleanVisitor visitor) 21 | { 22 | return b.Accept( 23 | new ChurchBooleanVisitor( 24 | trueCase : visitor.VisitFalse, 25 | falseCase : visitor.VisitTrue)); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /ChurchEncoding/ChurchOr.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ploeh.Samples.ChurchEncoding 8 | { 9 | public class ChurchOr : IChurchBoolean 10 | { 11 | private readonly IChurchBoolean x; 12 | private readonly IChurchBoolean y; 13 | 14 | public ChurchOr(IChurchBoolean x, IChurchBoolean y) 15 | { 16 | this.x = x; 17 | this.y = y; 18 | } 19 | 20 | public T Accept(ChurchBooleanVisitor visitor) 21 | { 22 | return x.Accept( 23 | new ChurchBooleanVisitor( 24 | visitor.VisitTrue, 25 | y.Accept(visitor))); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /ChurchEncoding/ChurchTrue.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ploeh.Samples.ChurchEncoding 8 | { 9 | public class ChurchTrue : IChurchBoolean 10 | { 11 | public T Accept(ChurchBooleanVisitor visitor) 12 | { 13 | return visitor.VisitTrue; 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /ChurchEncoding/Either.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ploeh.Samples.ChurchEncoding 8 | { 9 | public static class Either 10 | { 11 | // Bifunctor 12 | public static IEither SelectBoth( 13 | this IEither source, 14 | Func selectLeft, 15 | Func selectRight) 16 | { 17 | return source.Accept( 18 | new SelectBothVisitor(selectLeft, selectRight)); 19 | } 20 | 21 | private class SelectBothVisitor : 22 | IEitherVisitor> 23 | { 24 | private readonly Func selectLeft; 25 | private readonly Func selectRight; 26 | 27 | public SelectBothVisitor( 28 | Func selectLeft, 29 | Func selectRight) 30 | { 31 | this.selectLeft = selectLeft; 32 | this.selectRight = selectRight; 33 | } 34 | 35 | public IEither VisitLeft(L left) 36 | { 37 | return new Left(selectLeft(left)); 38 | } 39 | 40 | public IEither VisitRight(R right) 41 | { 42 | return new Right(selectRight(right)); 43 | } 44 | } 45 | 46 | public static IEither SelectLeft( 47 | this IEither source, 48 | Func selector) 49 | { 50 | return source.SelectBoth(selector, r => r); 51 | } 52 | 53 | public static IEither SelectRight( 54 | this IEither source, 55 | Func selector) 56 | { 57 | return source.SelectBoth(l => l, selector); 58 | } 59 | 60 | // Functor 61 | public static IEither Select( 62 | this IEither source, 63 | Func selector) 64 | { 65 | return source.SelectRight(selector); 66 | } 67 | 68 | // Monad 69 | public static IEither Join( 70 | this IEither> source) 71 | { 72 | return source.Accept(new JoinVisitor()); 73 | } 74 | 75 | private class JoinVisitor : 76 | IEitherVisitor, IEither> 77 | { 78 | public IEither VisitLeft(L left) 79 | { 80 | return new Left(left); 81 | } 82 | 83 | public IEither VisitRight(IEither right) 84 | { 85 | return right; 86 | } 87 | } 88 | 89 | public static IEither SelectMany( 90 | this IEither source, 91 | Func> selector) 92 | { 93 | return source.Select(selector).Join(); 94 | } 95 | 96 | public static IEither SelectMany( 97 | this IEither source, 98 | Func> k, 99 | Func s) 100 | { 101 | return source.SelectMany(x => k(x).Select(y => s(x, y))); 102 | } 103 | 104 | // Bifoldable - sort of... Really, the T involved should give rise to a 105 | // monoid 106 | public static T Bifold(this IEither source) 107 | { 108 | return source.Accept(new BifoldVisitor()); 109 | } 110 | 111 | private class BifoldVisitor : IEitherVisitor 112 | { 113 | public T VisitLeft(T left) 114 | { 115 | return left; 116 | } 117 | 118 | public T VisitRight(T right) 119 | { 120 | return right; 121 | } 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /ChurchEncoding/EitherTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Xunit; 7 | 8 | namespace Ploeh.Samples.ChurchEncoding 9 | { 10 | public class EitherTests 11 | { 12 | [Fact] 13 | public void MatchRight() 14 | { 15 | IEither sut = new Right(42); 16 | var actual = sut.Accept(new MatchVisitor()); 17 | Assert.Equal("42", actual); 18 | } 19 | 20 | [Fact] 21 | public void MatchLeft() 22 | { 23 | IEither sut = new Left("foo"); 24 | var actual = sut.Accept(new MatchVisitor()); 25 | Assert.Equal("foo", actual); 26 | } 27 | 28 | private class MatchVisitor : IEitherVisitor 29 | { 30 | public string VisitLeft(string left) 31 | { 32 | return left; 33 | } 34 | 35 | public string VisitRight(int right) 36 | { 37 | return right.ToString(); 38 | } 39 | } 40 | 41 | public enum VoteError 42 | { 43 | Empty = 0, 44 | Tie 45 | } 46 | 47 | public static IEither FindWinner(IReadOnlyCollection votes) 48 | { 49 | var countedVotes = from v in votes 50 | group v by v into g 51 | let count = g.Count() 52 | orderby count descending 53 | select new { Vote = g.Key, Count = count }; 54 | var c = countedVotes.Take(2).Count(); 55 | 56 | if (c == 0) 57 | return new Left(VoteError.Empty); 58 | 59 | var x0 = countedVotes.ElementAt(0); 60 | if (c == 1) 61 | return new Right(x0.Vote); 62 | 63 | var x1 = countedVotes.ElementAt(1); 64 | if (Equals(x0.Count, x1.Count)) 65 | return new Left(VoteError.Tie); 66 | 67 | return new Right(x0.Vote); 68 | } 69 | 70 | public static IEither FindWinner(params T[] votes) 71 | { 72 | return FindWinner((IReadOnlyCollection)votes); 73 | } 74 | 75 | [Theory] 76 | [InlineData(new string[0], "Empty")] 77 | [InlineData(new[] { "Foo" }, "Foo")] 78 | [InlineData(new[] { "Foo", "Bar" }, "Tie")] 79 | [InlineData(new[] { "Foo", "Bar", "Bar" }, "Bar")] 80 | [InlineData(new[] { "Foo", "Bar", "Foo" }, "Foo")] 81 | [InlineData(new[] { "Foo", "Bar", "Baz" }, "Tie")] 82 | [InlineData(new[] { "Foo", "Bar", "Bar", "Foo" }, "Tie")] 83 | [InlineData(new[] { "Foo", "Bar", "Baz", "Foo" }, "Foo")] 84 | public void FindWinnerReturnsCorrectResult(string[] votes, string expected) 85 | { 86 | var actual = FindWinner(votes); 87 | Assert.Equal(expected, actual.Accept(new FindWinnerVisitor())); 88 | } 89 | 90 | private class FindWinnerVisitor : IEitherVisitor 91 | { 92 | public string VisitLeft(VoteError left) 93 | { 94 | return left.ToString(); 95 | } 96 | 97 | public string VisitRight(string right) 98 | { 99 | return right; 100 | } 101 | } 102 | 103 | [Fact] 104 | public void SelectLeft() 105 | { 106 | IEither sut = new Left(1337); 107 | var actual = sut.SelectLeft(i => i % 2 != 0); 108 | Assert.True(actual.Bifold()); 109 | } 110 | 111 | [Fact] 112 | public void SelectRight() 113 | { 114 | IEither sut = new Right("foo"); 115 | var actual = sut.SelectRight(s => s.StartsWith("f")); 116 | Assert.True(actual.Bifold()); 117 | } 118 | 119 | private static T Id(T x) => x; 120 | 121 | public static IEnumerable BifunctorLawsData 122 | { 123 | get 124 | { 125 | yield return new[] { new Left("foo") }; 126 | yield return new[] { new Left("bar") }; 127 | yield return new[] { new Left("baz") }; 128 | yield return new[] { new Right( 42) }; 129 | yield return new[] { new Right( 1337) }; 130 | yield return new[] { new Right( 0) }; 131 | } 132 | } 133 | 134 | [Theory, MemberData(nameof(BifunctorLawsData))] 135 | public void SelectLeftObeysFirstFunctorLaw(IEither e) 136 | { 137 | Assert.Equal(e, e.SelectLeft(Id)); 138 | } 139 | 140 | [Theory, MemberData(nameof(BifunctorLawsData))] 141 | public void SelectRightObeysFirstFunctorLaw(IEither e) 142 | { 143 | Assert.Equal(e, e.SelectRight(Id)); 144 | } 145 | 146 | [Theory, MemberData(nameof(BifunctorLawsData))] 147 | public void SelectBothObeysIdentityLaw(IEither e) 148 | { 149 | Assert.Equal(e, e.SelectBoth(Id, Id)); 150 | } 151 | 152 | [Theory, MemberData(nameof(BifunctorLawsData))] 153 | public void ConsistencyLawHolds(IEither e) 154 | { 155 | bool f(string s) => string.IsNullOrWhiteSpace(s); 156 | DateTime g(int i) => new DateTime(i); 157 | 158 | Assert.Equal(e.SelectBoth(f, g), e.SelectRight(g).SelectLeft(f)); 159 | Assert.Equal( 160 | e.SelectLeft(f).SelectRight(g), 161 | e.SelectRight(g).SelectLeft(f)); 162 | } 163 | 164 | [Theory, MemberData(nameof(BifunctorLawsData))] 165 | public void SecondFunctorLawHoldsForSelectLeft(IEither e) 166 | { 167 | bool f(int x) => x % 2 == 0; 168 | int g(string s) => s.Length; 169 | 170 | Assert.Equal( 171 | e.SelectLeft(x => f(g(x))), 172 | e.SelectLeft(g).SelectLeft(f)); 173 | } 174 | 175 | [Theory, MemberData(nameof(BifunctorLawsData))] 176 | public void SecondFunctorLawHoldsForSelectRight(IEither e) 177 | { 178 | char f(bool b) => b ? 'T' : 'F'; 179 | bool g(int i) => i % 2 == 0; 180 | 181 | Assert.Equal( 182 | e.SelectRight(x => f(g(x))), 183 | e.SelectRight(g).SelectRight(f)); 184 | } 185 | 186 | [Theory, MemberData(nameof(BifunctorLawsData))] 187 | public void SelectBothCompositionLawHolds(IEither e) 188 | { 189 | bool f(int x) => x % 2 == 0; 190 | int g(string s) => s.Length; 191 | char h(bool b) => b ? 'T' : 'F'; 192 | bool i(int x) => x % 2 == 0; 193 | 194 | Assert.Equal( 195 | e.SelectBoth(x => f(g(x)), y => h(i(y))), 196 | e.SelectBoth(g, i).SelectBoth(f, h)); 197 | } 198 | 199 | [Fact] 200 | public void UseSimpleQuerySyntax() 201 | { 202 | IEither actual = from s in new Right("foo") 203 | select s.Length; 204 | Assert.Equal(new Right(3), actual); 205 | } 206 | 207 | [Fact] 208 | public void FindWinnerQuerySyntaxExample() 209 | { 210 | IEither isVotePositive = 211 | from i in FindWinner(1, 2, -3, -1, 2, -1, -1) 212 | select i > 0; 213 | Assert.Equal(new Right(false), isVotePositive); 214 | } 215 | 216 | [Fact] 217 | public void UseCartesianQuerySyntax() 218 | { 219 | var actual = from x in new Right(42) 220 | from y in new Left("foo") 221 | select Math.Pow(x, y); 222 | Assert.Equal("foo", actual.Select(_ => "bar").Bifold()); 223 | } 224 | 225 | public static IEither TryParseDate(string candidate) 226 | { 227 | if (DateTime.TryParse(candidate, out var d)) 228 | return new Right(d); 229 | else 230 | return new Left(candidate); 231 | } 232 | 233 | public static IEither TryParseDuration(string candidate) 234 | { 235 | if (TimeSpan.TryParse(candidate, out var ts)) 236 | return new Right(ts); 237 | else 238 | return new Left(candidate); 239 | } 240 | 241 | [Fact] 242 | public void NestedParsingExample() 243 | { 244 | IEither dt = TryParseDate("2022-03-21"); 245 | IEither ts = TryParseDuration("2"); 246 | 247 | IEither result = 248 | from d in dt 249 | from dur in ts 250 | select d + dur; 251 | 252 | Assert.Equal( 253 | new Right(new DateTime(2022, 3, 23)), 254 | result); 255 | } 256 | 257 | [Theory] 258 | [InlineData("2")] 259 | [InlineData("2.3:00")] 260 | [InlineData("4.5:30")] 261 | [InlineData("0:33:44")] 262 | [InlineData("foo")] 263 | public void LeftIdentityLaw(string a) 264 | { 265 | Func> @return = s => new Right(s); 266 | Func> h = TryParseDuration; 267 | 268 | Assert.Equal(@return(a).SelectMany(h), h(a)); 269 | } 270 | 271 | [Theory] 272 | [InlineData("2022-03-22")] 273 | [InlineData("2022-03-21T16:57")] 274 | [InlineData("bar")] 275 | public void RightIdentityLaw(string a) 276 | { 277 | Func> f = TryParseDate; 278 | Func> @return = d => new Right(d); 279 | 280 | IEither m = f(a); 281 | 282 | Assert.Equal(m.SelectMany(@return), m); 283 | } 284 | 285 | public static IEither DaysForward(TimeSpan ts) 286 | { 287 | if (ts < TimeSpan.Zero) 288 | return new Left($"Negative durations not allowed: {ts}."); 289 | 290 | return new Right(ts.TotalDays); 291 | } 292 | 293 | public static IEither Nat(double d) 294 | { 295 | if (d % 1 != 0) 296 | return new Left($"Non-integers not allowed: {d}."); 297 | if (d < 1) 298 | return new Left($"Non-positive numbers not allowed: {d}."); 299 | 300 | return new Right((int)d); 301 | } 302 | 303 | [Theory] 304 | [InlineData("2")] 305 | [InlineData("-2.3:00")] 306 | [InlineData("4.5:30")] 307 | [InlineData("0:33:44")] 308 | [InlineData("0")] 309 | [InlineData("foo")] 310 | public void AssociativityLaw(string a) 311 | { 312 | Func> f = TryParseDuration; 313 | Func> g = DaysForward; 314 | Func> h = Nat; 315 | 316 | var m = f(a); 317 | 318 | Assert.Equal(m.SelectMany(g).SelectMany(h), m.SelectMany(x => g(x).SelectMany(h))); 319 | } 320 | } 321 | } 322 | -------------------------------------------------------------------------------- /ChurchEncoding/FromMaybeVisitor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ploeh.Samples.ChurchEncoding 8 | { 9 | // Does the same work as Haskell's Data.Maybe.fromMaybe function, hence the 10 | // name. 11 | public class FromMaybeVisitor : IMaybeVisitor 12 | { 13 | private readonly T nothingResult; 14 | 15 | public FromMaybeVisitor(T nothingResult) 16 | { 17 | this.nothingResult = nothingResult; 18 | } 19 | 20 | public T VisitNothing 21 | { 22 | get { return nothingResult; } 23 | } 24 | 25 | public T VisitJust(T just) 26 | { 27 | return just; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /ChurchEncoding/IBinaryTree.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ploeh.Samples.ChurchEncoding 8 | { 9 | public interface IBinaryTree 10 | { 11 | TResult Match( 12 | Func node, 13 | Func leaf); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /ChurchEncoding/IChurchBoolean.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ploeh.Samples.ChurchEncoding 8 | { 9 | public interface IChurchBoolean 10 | { 11 | T Accept(ChurchBooleanVisitor visitor); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /ChurchEncoding/IEither.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ploeh.Samples.ChurchEncoding 8 | { 9 | public interface IEither 10 | { 11 | T Accept(IEitherVisitor visitor); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /ChurchEncoding/IEitherVisitor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ploeh.Samples.ChurchEncoding 8 | { 9 | public interface IEitherVisitor 10 | { 11 | T VisitLeft(L left); 12 | T VisitRight(R right); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /ChurchEncoding/IMaybe.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ploeh.Samples.ChurchEncoding 8 | { 9 | public interface IMaybe 10 | { 11 | TResult Accept(IMaybeVisitor visitor); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /ChurchEncoding/IMaybeVisitor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ploeh.Samples.ChurchEncoding 8 | { 9 | public interface IMaybeVisitor 10 | { 11 | TResult VisitNothing { get; } 12 | 13 | TResult VisitJust(T just); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /ChurchEncoding/INaturalNumber.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ploeh.Samples.ChurchEncoding 8 | { 9 | public interface INaturalNumber 10 | { 11 | T Accept(INaturalNumberVisitor visitor); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /ChurchEncoding/INaturalNumberVisitor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ploeh.Samples.ChurchEncoding 8 | { 9 | public interface INaturalNumberVisitor 10 | { 11 | T VisitZero { get; } 12 | T VisitSucc(INaturalNumber predecessor); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /ChurchEncoding/IRoseTree.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ploeh.Samples.ChurchEncoding 8 | { 9 | public interface IRoseTree 10 | { 11 | TResult Accept(IRoseTreeVisitor visitor); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /ChurchEncoding/IRoseTreeVisitor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ploeh.Samples.ChurchEncoding 8 | { 9 | public interface IRoseTreeVisitor 10 | { 11 | T VisitNode(N node, IEnumerable> branches); 12 | T VisitLeaf(L leaf); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /ChurchEncoding/Just.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Ploeh.Samples.ChurchEncoding 9 | { 10 | [DebuggerDisplay("{ value }")] 11 | public class Just : IMaybe 12 | { 13 | private readonly T value; 14 | 15 | public Just(T value) 16 | { 17 | this.value = value; 18 | } 19 | 20 | public TResult Accept(IMaybeVisitor visitor) 21 | { 22 | return visitor.VisitJust(value); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /ChurchEncoding/Leaf.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ploeh.Samples.ChurchEncoding 8 | { 9 | public sealed class Leaf : IBinaryTree 10 | { 11 | private readonly T item; 12 | 13 | public Leaf(T item) 14 | { 15 | if (item == null) 16 | throw new ArgumentNullException(nameof(item)); 17 | 18 | this.item = item; 19 | } 20 | 21 | public TResult Match( 22 | Func node, 23 | Func leaf) 24 | { 25 | return leaf(item); 26 | } 27 | 28 | public override bool Equals(object obj) 29 | { 30 | if (!(obj is Leaf other)) 31 | return false; 32 | 33 | return Equals(item, other.item); 34 | } 35 | 36 | public override int GetHashCode() 37 | { 38 | return item.GetHashCode(); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /ChurchEncoding/Left.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Ploeh.Samples.ChurchEncoding 9 | { 10 | [DebuggerDisplay("{ left }")] 11 | public sealed class Left : IEither 12 | { 13 | private readonly L left; 14 | 15 | public Left(L left) 16 | { 17 | this.left = left; 18 | } 19 | 20 | public T Accept(IEitherVisitor visitor) 21 | { 22 | return visitor.VisitLeft(left); 23 | } 24 | 25 | public override bool Equals(object obj) 26 | { 27 | if (!(obj is Left other)) 28 | return false; 29 | 30 | return Equals(left, other.left); 31 | } 32 | 33 | public override int GetHashCode() 34 | { 35 | return left.GetHashCode(); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /ChurchEncoding/Maybe.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ploeh.Samples.ChurchEncoding 8 | { 9 | public static class Maybe 10 | { 11 | public static IChurchBoolean IsNothing(this IMaybe m) 12 | { 13 | return m.Accept(new IsNothingMaybeVisitor()); 14 | } 15 | 16 | private class IsNothingMaybeVisitor : 17 | IMaybeVisitor 18 | { 19 | public IChurchBoolean VisitNothing 20 | { 21 | get { return new ChurchTrue(); } 22 | } 23 | 24 | public IChurchBoolean VisitJust(T just) 25 | { 26 | return new ChurchFalse(); 27 | } 28 | } 29 | 30 | public static IChurchBoolean IsJust(this IMaybe m) 31 | { 32 | return m.Accept(new IsJustMaybeVisitor()); 33 | } 34 | 35 | private class IsJustMaybeVisitor : IMaybeVisitor 36 | { 37 | public IChurchBoolean VisitNothing 38 | { 39 | get { return new ChurchFalse(); } 40 | } 41 | 42 | public IChurchBoolean VisitJust(T just) 43 | { 44 | return new ChurchTrue(); 45 | } 46 | } 47 | 48 | // Functor 49 | public static IMaybe Select( 50 | this IMaybe source, 51 | Func selector) 52 | { 53 | return source.Accept(new SelectMaybeVisitor(selector)); 54 | } 55 | 56 | private class SelectMaybeVisitor : 57 | IMaybeVisitor> 58 | { 59 | private readonly Func selector; 60 | 61 | public SelectMaybeVisitor(Func selector) 62 | { 63 | this.selector = selector; 64 | } 65 | 66 | public IMaybe VisitNothing 67 | { 68 | get { return new Nothing(); } 69 | } 70 | 71 | public IMaybe VisitJust(T just) 72 | { 73 | return new Just(this.selector(just)); 74 | } 75 | } 76 | 77 | // Monad 78 | public static IMaybe Flatten(this IMaybe> source) 79 | { 80 | return source.Accept(new FlattenMaybeVisitor()); 81 | } 82 | 83 | private class FlattenMaybeVisitor : 84 | IMaybeVisitor, IMaybe> 85 | { 86 | public IMaybe VisitNothing 87 | { 88 | get { return new Nothing(); } 89 | } 90 | 91 | public IMaybe VisitJust(IMaybe just) 92 | { 93 | return just; 94 | } 95 | } 96 | 97 | public static IMaybe SelectMany( 98 | this IMaybe source, 99 | Func> selector) 100 | { 101 | return source.Select(selector).Flatten(); 102 | } 103 | 104 | public static IMaybe SelectMany( 105 | this IMaybe source, 106 | Func> k, 107 | Func s) 108 | { 109 | return source 110 | .SelectMany(x => k(x) 111 | .SelectMany(y => new Just(s(x, y)))); 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /ChurchEncoding/MaybeTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Xunit; 7 | 8 | namespace Ploeh.Samples.ChurchEncoding 9 | { 10 | public class MaybeTests 11 | { 12 | [Fact] 13 | public void MatchEmpty() 14 | { 15 | IMaybe sut = new Nothing(); 16 | var actual = sut.Accept(new MatchEmptyMaybeVisitor()); 17 | Assert.Equal("empty", actual); 18 | } 19 | 20 | private class MatchEmptyMaybeVisitor : 21 | IMaybeVisitor 22 | { 23 | public string VisitNothing 24 | { 25 | get { return "empty"; } 26 | } 27 | 28 | public string VisitJust(T just) 29 | { 30 | return "not empty"; 31 | } 32 | } 33 | 34 | [Fact] 35 | public void MatchFilled() 36 | { 37 | IMaybe sut = new Just(42); 38 | var actual = sut.Accept(new MatchFilledMaybeVisitor()); 39 | Assert.Equal("42", actual); 40 | } 41 | 42 | private class MatchFilledMaybeVisitor : 43 | IMaybeVisitor 44 | { 45 | public string VisitNothing 46 | { 47 | get { return "empty"; } 48 | } 49 | 50 | public string VisitJust(T just) 51 | { 52 | return just.ToString(); 53 | } 54 | } 55 | 56 | [Fact] 57 | public void SimpleQueryExpressionWorks() 58 | { 59 | IMaybe sut = new Just(42); 60 | IMaybe actual = from i in sut 61 | select i.ToString(); 62 | Assert.Equal( 63 | "42", 64 | actual.Accept(new FromMaybeVisitor("nothing"))); 65 | } 66 | 67 | [Fact] 68 | public void MultiplyTwoNaturalNumbersUsingQueryExpression() 69 | { 70 | var mx = new Just(NaturalNumber.Nine); 71 | var my = new Just(NaturalNumber.Four); 72 | 73 | var actual = from x in mx 74 | from y in my 75 | select x.Multiply(y); 76 | 77 | Assert.Equal( 78 | 36, 79 | actual 80 | .Accept( 81 | new FromMaybeVisitor( 82 | NaturalNumber.Zero)) 83 | .Count()); 84 | } 85 | 86 | public static IMaybe TryParse(string s) 87 | { 88 | int i; 89 | if (int.TryParse(s, out i)) 90 | return new Just(i); 91 | 92 | return new Nothing(); 93 | } 94 | 95 | public static IMaybe Sqrt(double d) 96 | { 97 | var result = Math.Sqrt(d); 98 | switch (result) 99 | { 100 | case double.NaN: 101 | return new Nothing(); 102 | case double.PositiveInfinity: 103 | return new Nothing(); 104 | default: 105 | return new Just(result); 106 | } 107 | } 108 | 109 | [Fact] 110 | public void TryParseSqrtFlattenExample() 111 | { 112 | var actual = TryParse("49").Select(i => Sqrt(i)).Flatten(); 113 | Assert.Equal(7, actual.Accept(new FromMaybeVisitor(0))); 114 | } 115 | 116 | [Fact] 117 | public void TryParseSqrtQueryExpressionExample() 118 | { 119 | var actual = from i in TryParse("49") 120 | from d in Sqrt(i) 121 | select d; 122 | Assert.Equal(7, actual.Accept(new FromMaybeVisitor(0))); 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /ChurchEncoding/NatualNumberTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Xunit; 7 | 8 | namespace Ploeh.Samples.ChurchEncoding 9 | { 10 | public class NatualNumberTests 11 | { 12 | [Fact] 13 | public void CountZero() 14 | { 15 | var zero = new Zero(); 16 | var actual = zero.Count(); 17 | Assert.Equal(0, actual); 18 | } 19 | 20 | [Fact] 21 | public void CountOne() 22 | { 23 | var one = new Successor(new Zero()); 24 | var actual = one.Count(); 25 | Assert.Equal(1, actual); 26 | } 27 | 28 | [Fact] 29 | public void CountTwo() 30 | { 31 | var two = new Successor(new Successor(new Zero())); 32 | var actual = two.Count(); 33 | Assert.Equal(2, actual); 34 | } 35 | 36 | [Fact] 37 | public void CountThree() 38 | { 39 | var three = 40 | new Successor(new Successor(new Successor(new Zero()))); 41 | var actual = three.Count(); 42 | Assert.Equal(3, actual); 43 | } 44 | 45 | [Fact] 46 | public void TwoPlusThreeIsFive() 47 | { 48 | var two = new Successor(new Successor(new Zero())); 49 | var three = 50 | new Successor(new Successor(new Successor(new Zero()))); 51 | 52 | var actual = two.Add(three); 53 | 54 | Assert.Equal(5, actual.Count()); 55 | } 56 | 57 | [Fact] 58 | public void OnePlusTwoPlusThreeIsSix() 59 | { 60 | var one = new Successor(new Zero()); 61 | var two = new Successor(new Successor(new Zero())); 62 | var three = 63 | new Successor(new Successor(new Successor(new Zero()))); 64 | 65 | var actual = one.Add(two).Add(three); 66 | 67 | Assert.Equal(6, actual.Count()); 68 | } 69 | 70 | [Fact] 71 | public void ZeroIsEven() 72 | { 73 | var zero = new Zero(); 74 | var actual = zero.IsEven(); 75 | Assert.True(actual.ToBool()); 76 | } 77 | 78 | [Fact] 79 | public void OneIsNotEven() 80 | { 81 | var one = new Successor(new Zero()); 82 | var actual = one.IsEven(); 83 | Assert.False(actual.ToBool()); 84 | } 85 | 86 | [Fact] 87 | public void TwoIsEven() 88 | { 89 | var two = new Successor(new Successor(new Zero())); 90 | var actual = two.IsEven(); 91 | Assert.True(actual.ToBool()); 92 | } 93 | 94 | [Fact] 95 | public void ThreeIsNotEven() 96 | { 97 | var three = 98 | new Successor(new Successor(new Successor(new Zero()))); 99 | var actual = three.IsEven(); 100 | Assert.False(actual.ToBool()); 101 | } 102 | 103 | [Fact] 104 | public void SixIsNotOdd() 105 | { 106 | var six = 107 | new Successor( // 6 108 | new Successor( // 5 109 | new Successor( // 4 110 | new Successor( // 3 111 | new Successor( // 2 112 | new Successor( // 1 113 | new Zero())))))); // 0 114 | var actual = six.IsOdd(); 115 | Assert.False(actual.ToBool()); 116 | } 117 | 118 | [Fact] 119 | public void SevenIsOdd() 120 | { 121 | var seven = 122 | new Successor( // 7 123 | new Successor( // 6 124 | new Successor( // 5 125 | new Successor( // 4 126 | new Successor( // 3 127 | new Successor( // 2 128 | new Successor( // 1 129 | new Zero()))))))); // 0 130 | var actual = seven.IsOdd(); 131 | Assert.True(actual.ToBool()); 132 | } 133 | 134 | [Fact] 135 | public void SixTimesSevenIsFortyTwo() 136 | { 137 | var actual = NaturalNumber.Six.Multiply(NaturalNumber.Seven); 138 | Assert.Equal(42, actual.Count()); 139 | } 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /ChurchEncoding/NaturalNumber.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ploeh.Samples.ChurchEncoding 8 | { 9 | public static class NaturalNumber 10 | { 11 | public static INaturalNumber Zero = new Zero(); 12 | public static INaturalNumber One = new Successor(Zero); 13 | public static INaturalNumber Two = new Successor(One); 14 | public static INaturalNumber Three = new Successor(Two); 15 | public static INaturalNumber Four = new Successor(Three); 16 | public static INaturalNumber Five = new Successor(Four); 17 | public static INaturalNumber Six = new Successor(Five); 18 | public static INaturalNumber Seven = new Successor(Six); 19 | public static INaturalNumber Eight = new Successor(Seven); 20 | public static INaturalNumber Nine = new Successor(Eight); 21 | 22 | // More memmbers go here... 23 | 24 | public static int Count(this INaturalNumber n) 25 | { 26 | return n.Accept(new CountNaturalNumberVisitor()); 27 | } 28 | 29 | private class CountNaturalNumberVisitor : 30 | INaturalNumberVisitor 31 | { 32 | public int VisitZero 33 | { 34 | get { return 0; } 35 | } 36 | 37 | public int VisitSucc(INaturalNumber predecessor) 38 | { 39 | return 1 + predecessor.Count(); 40 | } 41 | } 42 | 43 | public static INaturalNumber Add( 44 | this INaturalNumber x, 45 | INaturalNumber y) 46 | { 47 | return x.Accept(new AddNaturalNumberVisitor(y)); 48 | } 49 | 50 | private class AddNaturalNumberVisitor : 51 | INaturalNumberVisitor 52 | { 53 | private readonly INaturalNumber other; 54 | 55 | public AddNaturalNumberVisitor(INaturalNumber other) 56 | { 57 | this.other = other; 58 | } 59 | 60 | public INaturalNumber VisitZero 61 | { 62 | get { return other; } 63 | } 64 | 65 | public INaturalNumber VisitSucc(INaturalNumber predecessor) 66 | { 67 | return new Successor(predecessor.Add(other)); 68 | } 69 | } 70 | 71 | // The formula used here is 72 | // x * y = 1 + (x - 1) + (y - 1) + ((x - 1) * (y - 1)) 73 | // It follows like this: 74 | // x* y = 75 | // (x - 1 + 1) * (y - 1 + 1) = 76 | // ((x - 1) + 1) * ((y - 1) + 1) = 77 | // ((x - 1) * (y - 1)) + ((x - 1) * 1) + ((y - 1) * 1) + 1 * 1 = 78 | // ((x - 1) * (y - 1)) + (x - 1) + (y - 1) + 1 79 | public static INaturalNumber Multiply( 80 | this INaturalNumber x, 81 | INaturalNumber y) 82 | { 83 | return x.Accept(new MultiplyNaturalNumberVisitor(y)); 84 | } 85 | 86 | private class MultiplyNaturalNumberVisitor : 87 | INaturalNumberVisitor 88 | { 89 | private readonly INaturalNumber other; 90 | 91 | public MultiplyNaturalNumberVisitor(INaturalNumber other) 92 | { 93 | this.other = other; 94 | } 95 | 96 | public INaturalNumber VisitZero 97 | { 98 | get { return new Zero(); } 99 | } 100 | 101 | public INaturalNumber VisitSucc(INaturalNumber predecessor) 102 | { 103 | return this.other.Accept( 104 | new MultiplyOtherNaturalNumberVisitor(predecessor)); 105 | } 106 | 107 | private class MultiplyOtherNaturalNumberVisitor : 108 | INaturalNumberVisitor 109 | { 110 | private readonly INaturalNumber other; 111 | 112 | public MultiplyOtherNaturalNumberVisitor(INaturalNumber other) 113 | { 114 | this.other = other; 115 | } 116 | 117 | public INaturalNumber VisitZero 118 | { 119 | get { return new Zero(); } 120 | } 121 | 122 | public INaturalNumber VisitSucc(INaturalNumber predecessor) 123 | { 124 | return 125 | One 126 | .Add(other) 127 | .Add(predecessor) 128 | .Add(other.Multiply(predecessor)); 129 | } 130 | } 131 | } 132 | 133 | public static IChurchBoolean IsZero(this INaturalNumber n) 134 | { 135 | return n.Accept(new IsZeroNaturalNumberVisitor()); 136 | } 137 | 138 | private class IsZeroNaturalNumberVisitor : 139 | INaturalNumberVisitor 140 | { 141 | public IChurchBoolean VisitZero 142 | { 143 | get { return new ChurchTrue(); } 144 | } 145 | 146 | public IChurchBoolean VisitSucc(INaturalNumber predecessor) 147 | { 148 | return new ChurchFalse(); 149 | } 150 | } 151 | 152 | public static IChurchBoolean IsEven(this INaturalNumber n) 153 | { 154 | return n.Accept(new IsEvenNaturalNumberVisitor()); 155 | } 156 | 157 | private class IsEvenNaturalNumberVisitor : 158 | INaturalNumberVisitor 159 | { 160 | // 0 is even, so true 161 | public IChurchBoolean VisitZero 162 | { 163 | get { return new ChurchTrue(); } 164 | } 165 | 166 | public IChurchBoolean VisitSucc(INaturalNumber predecessor) 167 | { 168 | // Match previous 169 | return predecessor.Accept( 170 | new IsEvenPredecessorNaturalNumberVisitor()); 171 | } 172 | 173 | private class IsEvenPredecessorNaturalNumberVisitor : 174 | INaturalNumberVisitor 175 | { 176 | // If 0, the successor was 1 177 | public IChurchBoolean VisitZero 178 | { 179 | get { return new ChurchFalse(); } 180 | } 181 | 182 | public IChurchBoolean VisitSucc(INaturalNumber predecessor) 183 | { 184 | // Evaluate previous' previous value 185 | return predecessor.IsEven(); 186 | } 187 | } 188 | } 189 | 190 | public static IChurchBoolean IsOdd(this INaturalNumber n) 191 | { 192 | return new ChurchNot(n.IsEven()); 193 | } 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /ChurchEncoding/Node.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ploeh.Samples.ChurchEncoding 8 | { 9 | public sealed class Node : IBinaryTree 10 | { 11 | private readonly IBinaryTree left; 12 | private readonly T item; 13 | private readonly IBinaryTree right; 14 | 15 | public Node(IBinaryTree left, T item, IBinaryTree right) 16 | { 17 | if (left == null) 18 | throw new ArgumentNullException(nameof(left)); 19 | if (item == null) 20 | throw new ArgumentNullException(nameof(item)); 21 | if (right == null) 22 | throw new ArgumentNullException(nameof(right)); 23 | 24 | this.left = left; 25 | this.item = item; 26 | this.right = right; 27 | } 28 | 29 | public TResult Match( 30 | Func node, 31 | Func leaf) 32 | { 33 | return node(left.Match(node, leaf), item, right.Match(node, leaf)); 34 | } 35 | 36 | public override bool Equals(object obj) 37 | { 38 | if (!(obj is Node other)) 39 | return false; 40 | 41 | return Equals(left, other.left) 42 | && Equals(item, other.item) 43 | && Equals(right, other.right); 44 | } 45 | 46 | public override int GetHashCode() 47 | { 48 | return left.GetHashCode() ^ item.GetHashCode() ^ right.GetHashCode(); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /ChurchEncoding/Nothing.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ploeh.Samples.ChurchEncoding 8 | { 9 | public class Nothing : IMaybe 10 | { 11 | public TResult Accept(IMaybeVisitor visitor) 12 | { 13 | return visitor.VisitNothing; 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /ChurchEncoding/PaymentExample/Child.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ploeh.Samples.ChurchEncoding.PaymentExample 8 | { 9 | public class Child : IPaymentType 10 | { 11 | private readonly ChildPaymentService childPaymentService; 12 | 13 | public Child(ChildPaymentService childPaymentService) 14 | { 15 | this.childPaymentService = childPaymentService; 16 | } 17 | 18 | public T Accept(IPaymentTypeVisitor visitor) 19 | { 20 | return visitor.VisitChild(childPaymentService); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ChurchEncoding/PaymentExample/ChildPaymentService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ploeh.Samples.ChurchEncoding.PaymentExample 8 | { 9 | public class ChildPaymentService 10 | { 11 | public ChildPaymentService( 12 | string originalTransactionKey, 13 | PaymentService paymentService) 14 | { 15 | OriginalTransactionKey = originalTransactionKey; 16 | PaymentService = paymentService; 17 | } 18 | 19 | public string OriginalTransactionKey { get; } 20 | 21 | public PaymentService PaymentService { get; } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ChurchEncoding/PaymentExample/IPaymentType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ploeh.Samples.ChurchEncoding.PaymentExample 8 | { 9 | public interface IPaymentType 10 | { 11 | T Accept(IPaymentTypeVisitor visitor); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /ChurchEncoding/PaymentExample/IPaymentTypeVisitor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ploeh.Samples.ChurchEncoding.PaymentExample 8 | { 9 | public interface IPaymentTypeVisitor 10 | { 11 | T VisitIndividual(PaymentService individual); 12 | T VisitParent(PaymentService parent); 13 | T VisitChild(ChildPaymentService child); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /ChurchEncoding/PaymentExample/Individual.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ploeh.Samples.ChurchEncoding.PaymentExample 8 | { 9 | public class Individual : IPaymentType 10 | { 11 | private readonly PaymentService paymentService; 12 | 13 | public Individual(PaymentService paymentService) 14 | { 15 | this.paymentService = paymentService; 16 | } 17 | 18 | public T Accept(IPaymentTypeVisitor visitor) 19 | { 20 | return visitor.VisitIndividual(paymentService); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ChurchEncoding/PaymentExample/Parent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ploeh.Samples.ChurchEncoding.PaymentExample 8 | { 9 | public class Parent : IPaymentType 10 | { 11 | private readonly PaymentService paymentService; 12 | 13 | public Parent(PaymentService paymentService) 14 | { 15 | this.paymentService = paymentService; 16 | } 17 | 18 | public T Accept(IPaymentTypeVisitor visitor) 19 | { 20 | return visitor.VisitParent(paymentService); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ChurchEncoding/PaymentExample/PaymentJsonModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ploeh.Samples.ChurchEncoding.PaymentExample 8 | { 9 | public class PaymentJsonModel 10 | { 11 | public string Name { get; set; } 12 | 13 | public string Action { get; set; } 14 | 15 | public IChurchBoolean StartRecurrent { get; set; } 16 | 17 | public IMaybe TransactionKey { get; set; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /ChurchEncoding/PaymentExample/PaymentService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ploeh.Samples.ChurchEncoding.PaymentExample 8 | { 9 | public class PaymentService 10 | { 11 | public PaymentService(string name, string action) 12 | { 13 | Name = name; 14 | Action = action; 15 | } 16 | 17 | public string Name { get; } 18 | 19 | public string Action { get; } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ChurchEncoding/PaymentExample/PaymentType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ploeh.Samples.ChurchEncoding.PaymentExample 8 | { 9 | public static class PaymentType 10 | { 11 | public static PaymentJsonModel ToJson(this IPaymentType payment) 12 | { 13 | return payment.Accept(new PaymentTypeToJsonVisitor()); 14 | } 15 | 16 | private class PaymentTypeToJsonVisitor : 17 | IPaymentTypeVisitor 18 | { 19 | public PaymentJsonModel VisitIndividual(PaymentService individual) 20 | { 21 | return new PaymentJsonModel 22 | { 23 | Name = individual.Name, 24 | Action = individual.Action, 25 | StartRecurrent = new ChurchFalse(), 26 | TransactionKey = new Nothing() 27 | }; 28 | } 29 | 30 | public PaymentJsonModel VisitParent(PaymentService parent) 31 | { 32 | return new PaymentJsonModel 33 | { 34 | Name = parent.Name, 35 | Action = parent.Action, 36 | StartRecurrent = new ChurchTrue(), 37 | TransactionKey = new Nothing() 38 | }; 39 | } 40 | 41 | public PaymentJsonModel VisitChild(ChildPaymentService child) 42 | { 43 | return new PaymentJsonModel 44 | { 45 | Name = child.PaymentService.Name, 46 | Action = child.PaymentService.Action, 47 | StartRecurrent = new ChurchFalse(), 48 | TransactionKey = 49 | new Just(child.OriginalTransactionKey) 50 | }; 51 | } 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /ChurchEncoding/PaymentExample/PaymentTypeTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Xunit; 7 | 8 | namespace Ploeh.Samples.ChurchEncoding.PaymentExample 9 | { 10 | public class PaymentTypeTests 11 | { 12 | [Fact] 13 | public void IndividualToJsonReturnsCorrectResult() 14 | { 15 | var sut = new Individual(new PaymentService("MasterCard", "Pay")); 16 | 17 | var actual = sut.ToJson(); 18 | 19 | Assert.Equal("MasterCard", actual.Name); 20 | Assert.Equal("Pay", actual.Action); 21 | Assert.False(actual.StartRecurrent.ToBool()); 22 | Assert.True(actual.TransactionKey.IsNothing().ToBool()); 23 | } 24 | 25 | [Fact] 26 | public void ParentToJsonReturnsCorrectResult() 27 | { 28 | var sut = new Parent(new PaymentService("MasterCard", "Pay")); 29 | 30 | var actual = sut.ToJson(); 31 | 32 | Assert.Equal("MasterCard", actual.Name); 33 | Assert.Equal("Pay", actual.Action); 34 | Assert.True(actual.StartRecurrent.ToBool()); 35 | Assert.True(actual.TransactionKey.IsNothing().ToBool()); 36 | } 37 | 38 | [Fact] 39 | public void ChildToJsonReturnsCorrectResult() 40 | { 41 | var sut = 42 | new Child( 43 | new ChildPaymentService( 44 | "12345", 45 | new PaymentService("MasterCard", "Pay"))); 46 | 47 | var actual = sut.ToJson(); 48 | 49 | Assert.Equal("MasterCard", actual.Name); 50 | Assert.Equal("Pay", actual.Action); 51 | Assert.False(actual.StartRecurrent.ToBool()); 52 | Assert.Equal( 53 | "12345", 54 | actual.TransactionKey.Accept( 55 | new FromMaybeVisitor(""))); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /ChurchEncoding/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("ChurchEncoding")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("ChurchEncoding")] 13 | [assembly: AssemblyCopyright("Copyright © 2018")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("26956fac-018b-41ee-99ae-144bed6f157a")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /ChurchEncoding/Right.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Ploeh.Samples.ChurchEncoding 9 | { 10 | [DebuggerDisplay("{ right }")] 11 | public sealed class Right : IEither 12 | { 13 | private readonly R right; 14 | 15 | public Right(R right) 16 | { 17 | this.right = right; 18 | } 19 | 20 | public T Accept(IEitherVisitor visitor) 21 | { 22 | return visitor.VisitRight(right); 23 | } 24 | 25 | public override bool Equals(object obj) 26 | { 27 | if (!(obj is Right other)) 28 | return false; 29 | 30 | return Equals(right, other.right); 31 | } 32 | 33 | public override int GetHashCode() 34 | { 35 | return right.GetHashCode(); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /ChurchEncoding/RoseLeaf.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Ploeh.Samples.ChurchEncoding 9 | { 10 | [DebuggerDisplay("{ value }")] 11 | public sealed class RoseLeaf : IRoseTree 12 | { 13 | private readonly L value; 14 | 15 | public RoseLeaf(L value) 16 | { 17 | this.value = value; 18 | } 19 | 20 | public TResult Accept( 21 | IRoseTreeVisitor visitor) 22 | { 23 | return visitor.VisitLeaf(value); 24 | } 25 | 26 | public override bool Equals(object obj) 27 | { 28 | if (!(obj is RoseLeaf other)) 29 | return false; 30 | 31 | return Equals(value, other.value); 32 | } 33 | 34 | public override int GetHashCode() 35 | { 36 | return value.GetHashCode(); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /ChurchEncoding/RoseNode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Ploeh.Samples.ChurchEncoding 9 | { 10 | [DebuggerDisplay("{ value }, { branches }")] 11 | public sealed class RoseNode : IRoseTree 12 | { 13 | private readonly N value; 14 | private readonly IEnumerable> branches; 15 | 16 | public RoseNode(N value, IEnumerable> branches) 17 | { 18 | this.value = value; 19 | this.branches = branches; 20 | } 21 | 22 | public TResult Accept( 23 | IRoseTreeVisitor visitor) 24 | { 25 | return visitor.VisitNode(value, branches); 26 | } 27 | 28 | public override bool Equals(object obj) 29 | { 30 | if (!(obj is RoseNode other)) 31 | return false; 32 | 33 | return Equals(value, other.value) 34 | && Enumerable.SequenceEqual(branches, other.branches); 35 | } 36 | 37 | public override int GetHashCode() 38 | { 39 | return value.GetHashCode() ^ branches.GetHashCode(); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /ChurchEncoding/RoseTree.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ploeh.Samples.ChurchEncoding 8 | { 9 | public static class RoseTree 10 | { 11 | public static IRoseTree Node( 12 | N value, 13 | params IRoseTree[] branches) 14 | { 15 | return new RoseNode(value, branches); 16 | } 17 | 18 | public static IChurchBoolean IsLeaf(this IRoseTree source) 19 | { 20 | return source.Accept(new IsLeafVisitor()); 21 | } 22 | 23 | private class IsLeafVisitor : 24 | IRoseTreeVisitor 25 | { 26 | public IChurchBoolean VisitLeaf(L leaf) 27 | { 28 | return new ChurchTrue(); 29 | } 30 | 31 | public IChurchBoolean VisitNode( 32 | N node, IEnumerable> branches) 33 | { 34 | return new ChurchFalse(); 35 | } 36 | } 37 | 38 | public static IChurchBoolean IsNode(this IRoseTree source) 39 | { 40 | return new ChurchNot(source.IsLeaf()); 41 | } 42 | 43 | public static TResult Cata( 44 | this IRoseTree tree, 45 | Func, TResult> node, 46 | Func leaf) 47 | { 48 | return tree.Accept(new CataVisitor(node, leaf)); 49 | } 50 | 51 | private class CataVisitor : IRoseTreeVisitor 52 | { 53 | private readonly Func, TResult> node; 54 | private readonly Func leaf; 55 | 56 | public CataVisitor( 57 | Func, TResult> node, 58 | Func leaf) 59 | { 60 | this.node = node; 61 | this.leaf = leaf; 62 | } 63 | 64 | public TResult VisitLeaf(L leaf) 65 | { 66 | return this.leaf(leaf); 67 | } 68 | 69 | public TResult VisitNode(N node, IEnumerable> branches) 70 | { 71 | return this.node( 72 | node, 73 | branches.Select(t => t.Cata(this.node, leaf))); 74 | } 75 | } 76 | 77 | // Bifunctor 78 | public static IRoseTree SelectBoth( 79 | this IRoseTree source, 80 | Func selectNode, 81 | Func selectLeaf) 82 | { 83 | return source.Cata( 84 | node: (n, branches) => new RoseNode(selectNode(n), branches), 85 | leaf: l => (IRoseTree)new RoseLeaf(selectLeaf(l))); 86 | } 87 | 88 | public static IRoseTree SelectNode( 89 | this IRoseTree source, 90 | Func selector) 91 | { 92 | return source.SelectBoth(selector, l => l); 93 | } 94 | 95 | public static IRoseTree SelectLeaf( 96 | this IRoseTree source, 97 | Func selector) 98 | { 99 | return source.SelectBoth(n => n, selector); 100 | } 101 | 102 | // Functor 103 | public static IRoseTree Select( 104 | this IRoseTree source, 105 | Func selector) 106 | { 107 | return source.SelectLeaf(selector); 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /ChurchEncoding/RoseTreeTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Xunit; 7 | 8 | namespace Ploeh.Samples.ChurchEncoding 9 | { 10 | public class RoseTreeTests 11 | { 12 | [Fact] 13 | public void MatchLeaf() 14 | { 15 | IRoseTree tree = new RoseLeaf(42); 16 | int actual = tree.Accept(new MatchIntLeafVisitor()); 17 | Assert.Equal(42, actual); 18 | } 19 | 20 | private class MatchIntLeafVisitor : 21 | IRoseTreeVisitor 22 | { 23 | public int VisitLeaf(int leaf) 24 | { 25 | return leaf; 26 | } 27 | 28 | public int VisitNode( 29 | string node, 30 | IEnumerable> branches) 31 | { 32 | return -1; 33 | } 34 | } 35 | 36 | [Fact] 37 | public void MatchNode() 38 | { 39 | IRoseTree tree = 40 | RoseTree.Node("foo", 41 | new RoseLeaf(42), 42 | new RoseLeaf(1337)); 43 | int actual = tree.Accept(new MatchStringNodeVisitor()); 44 | Assert.Equal(3, actual); 45 | } 46 | 47 | private class MatchStringNodeVisitor : 48 | IRoseTreeVisitor 49 | { 50 | public int VisitLeaf(int leaf) 51 | { 52 | return leaf; 53 | } 54 | 55 | public int VisitNode( 56 | string node, 57 | IEnumerable> branches) 58 | { 59 | return node.Length; 60 | } 61 | } 62 | 63 | [Fact] 64 | public void LeafIsLeaf() 65 | { 66 | var sut = new RoseLeaf(2); 67 | var actual = sut.IsLeaf(); 68 | Assert.True(actual.ToBool()); 69 | } 70 | 71 | [Fact] 72 | public void LeafIsNotNode() 73 | { 74 | var sut = new RoseLeaf(-4); 75 | var actual = sut.IsNode(); 76 | Assert.False(actual.ToBool()); 77 | } 78 | 79 | [Fact] 80 | public void NodeIsNode() 81 | { 82 | var sut = 83 | RoseTree.Node( 84 | new Guid(0x90B5DF4F, 0xE996, 0x416E, 0xB6, 0x77, 0xEF, 0x4F, 0x38, 0x5E, 0x03, 0xC3)); 85 | var actual = sut.IsNode(); 86 | Assert.True(actual.ToBool()); 87 | } 88 | 89 | [Fact] 90 | public void NodeIsNotLeaf() 91 | { 92 | var sut = RoseTree.Node(new Version(2, 0)); 93 | var actual = sut.IsLeaf(); 94 | Assert.False(actual.ToBool()); 95 | } 96 | 97 | [Fact] 98 | public void CataLeaf() 99 | { 100 | IRoseTree tree = new RoseLeaf(42); 101 | int actual = tree.Cata((x, xs) => x.Length + xs.Sum(), x => x); 102 | Assert.Equal(42, actual); 103 | } 104 | 105 | [Fact] 106 | public void CataNode() 107 | { 108 | IRoseTree tree = 109 | RoseTree.Node( 110 | "foo", 111 | new RoseLeaf(42), 112 | new RoseLeaf(1337)); 113 | int actual = tree.Cata((x, xs) => x.Length + xs.Sum(), x => x); 114 | Assert.Equal(1382, actual); 115 | } 116 | 117 | public class Unit 118 | { 119 | public readonly static Unit Instance = new Unit(); 120 | 121 | private Unit() { } 122 | } 123 | 124 | [Fact] 125 | public void UseMeertensTree() 126 | { 127 | IRoseTree meertensTree = 128 | RoseTree.Node(Unit.Instance, 129 | RoseTree.Node(Unit.Instance, 130 | RoseTree.Node(Unit.Instance, 131 | new RoseLeaf(2112)), 132 | new RoseLeaf(42), 133 | new RoseLeaf(1337), 134 | new RoseLeaf(90125)), 135 | RoseTree.Node(Unit.Instance, 136 | new RoseLeaf(1984)), 137 | new RoseLeaf(666)); 138 | Assert.False(meertensTree.IsLeaf().ToBool()); 139 | } 140 | 141 | private static readonly IRoseTree exampleTree = 142 | RoseTree.Node(42, 143 | RoseTree.Node(1337, 144 | new RoseLeaf("foo"), 145 | new RoseLeaf("bar")), 146 | RoseTree.Node(2112, 147 | RoseTree.Node(90125, 148 | new RoseLeaf("baz"), 149 | new RoseLeaf("qux"), 150 | new RoseLeaf("quux")), 151 | new RoseLeaf("quuz")), 152 | new RoseLeaf("corge")); 153 | 154 | [Fact] 155 | public void SumExample() 156 | { 157 | int actual = 158 | exampleTree.Cata((x, xs) => x + xs.Sum(), x => x.Length); 159 | Assert.Equal(93641, actual); 160 | } 161 | 162 | [Fact] 163 | public void LeafCountExample() 164 | { 165 | int actual = 166 | exampleTree.Cata((_, xs) => xs.Sum(), _ => 1); 167 | Assert.Equal(7, actual); 168 | } 169 | 170 | [Fact] 171 | public void MaximumDepthExample() 172 | { 173 | int actual = 174 | exampleTree.Cata((_, xs) => 1 + xs.Max(), _ => 0); 175 | Assert.Equal(3, actual); 176 | } 177 | 178 | private static T Id(T x) => x; 179 | 180 | public static IEnumerable BifunctorLawsData 181 | { 182 | get 183 | { 184 | yield return new[] { new RoseLeaf("") }; 185 | yield return new[] { new RoseLeaf("foo") }; 186 | yield return new[] { RoseTree.Node(42) }; 187 | yield return new[] { RoseTree.Node(42, new RoseLeaf("bar")) }; 188 | yield return new[] { exampleTree }; 189 | } 190 | } 191 | 192 | [Theory, MemberData(nameof(BifunctorLawsData))] 193 | public void SelectNodeObeysFirstFunctorLaw(IRoseTree t) 194 | { 195 | Assert.Equal(t, t.SelectNode(Id)); 196 | } 197 | 198 | [Theory, MemberData(nameof(BifunctorLawsData))] 199 | public void SelectLeafObeysFirstFunctorLaw(IRoseTree t) 200 | { 201 | Assert.Equal(t, t.SelectLeaf(Id)); 202 | } 203 | 204 | [Theory, MemberData(nameof(BifunctorLawsData))] 205 | public void SelectBothObeysIdentityLaw(IRoseTree t) 206 | { 207 | Assert.Equal(t, t.SelectBoth(Id, Id)); 208 | } 209 | 210 | [Theory, MemberData(nameof(BifunctorLawsData))] 211 | public void ConsistencyLawHolds(IRoseTree t) 212 | { 213 | DateTime f(int i) => new DateTime(i); 214 | bool g(string s) => string.IsNullOrWhiteSpace(s); 215 | 216 | Assert.Equal(t.SelectBoth(f, g), t.SelectLeaf(g).SelectNode(f)); 217 | Assert.Equal( 218 | t.SelectNode(f).SelectLeaf(g), 219 | t.SelectLeaf(g).SelectNode(f)); 220 | } 221 | 222 | [Theory, MemberData(nameof(BifunctorLawsData))] 223 | public void SecondFunctorLawHoldsForSelectNode(IRoseTree t) 224 | { 225 | char f(bool b) => b ? 'T' : 'F'; 226 | bool g(int i) => i % 2 == 0; 227 | 228 | Assert.Equal( 229 | t.SelectNode(x => f(g(x))), 230 | t.SelectNode(g).SelectNode(f)); 231 | } 232 | 233 | [Theory, MemberData(nameof(BifunctorLawsData))] 234 | public void SecondFunctorLawHoldsForSelectLeaf(IRoseTree t) 235 | { 236 | bool f(int x) => x % 2 == 0; 237 | int g(string s) => s.Length; 238 | 239 | Assert.Equal( 240 | t.SelectLeaf(x => f(g(x))), 241 | t.SelectLeaf(g).SelectLeaf(f)); 242 | } 243 | 244 | [Theory, MemberData(nameof(BifunctorLawsData))] 245 | public void SelectBothCompositionLawHolds(IRoseTree t) 246 | { 247 | char f(bool b) => b ? 'T' : 'F'; 248 | bool g(int x) => x % 2 == 0; 249 | bool h(int x) => x % 2 == 0; 250 | int i(string s) => s.Length; 251 | 252 | Assert.Equal( 253 | t.SelectBoth(x => f(g(x)), y => h(i(y))), 254 | t.SelectBoth(g, i).SelectBoth(f, h)); 255 | } 256 | 257 | [Fact] 258 | public void MenuExample() 259 | { 260 | IRoseTree editMenuTemplate = 261 | RoseTree.Node("Edit", 262 | RoseTree.Node("Find and Replace", 263 | new RoseLeaf("Find"), 264 | new RoseLeaf("Replace")), 265 | RoseTree.Node("Case", 266 | new RoseLeaf("Upper"), 267 | new RoseLeaf("Lower")), 268 | new RoseLeaf("Cut"), 269 | new RoseLeaf("Copy"), 270 | new RoseLeaf("Paste")); 271 | 272 | var commandStore = new CommandStore(); 273 | IRoseTree editMenu = 274 | from name in editMenuTemplate 275 | select commandStore.Lookup(name); 276 | 277 | var roundTripped = from command in editMenu 278 | select command.Name; 279 | Assert.Equal(editMenuTemplate, roundTripped); 280 | } 281 | 282 | private class CommandStore 283 | { 284 | private readonly List commands; 285 | 286 | public CommandStore() 287 | { 288 | commands = new List 289 | { 290 | new FindCommand("Find"), 291 | new ReplaceCommand("Replace"), 292 | new UpperCaseCommand("Upper"), 293 | new LowerCaseCommand("Lower"), 294 | new CutCommand("Cut"), 295 | new CopyCommand("Copy"), 296 | new PasteCommand("Paste") 297 | }; 298 | } 299 | 300 | public Command Lookup(string name) 301 | { 302 | return commands 303 | .DefaultIfEmpty(new Command(name)) 304 | .FirstOrDefault(c => c.Name == name); 305 | } 306 | 307 | } 308 | 309 | public class Command 310 | { 311 | public Command(string name) 312 | { 313 | Name = name; 314 | } 315 | 316 | public string Name { get; } 317 | 318 | public virtual void Execute() 319 | { 320 | } 321 | } 322 | 323 | public class FindCommand : Command 324 | { 325 | public FindCommand(string name) : base(name) 326 | { 327 | } 328 | } 329 | 330 | public class ReplaceCommand : Command 331 | { 332 | public ReplaceCommand(string name) : base(name) 333 | { 334 | } 335 | } 336 | 337 | public class UpperCaseCommand : Command 338 | { 339 | public UpperCaseCommand(string name) : base(name) 340 | { 341 | } 342 | } 343 | 344 | public class LowerCaseCommand : Command 345 | { 346 | public LowerCaseCommand(string name) : base(name) 347 | { 348 | } 349 | } 350 | 351 | public class CutCommand : Command 352 | { 353 | public CutCommand(string name) : base(name) 354 | { 355 | } 356 | } 357 | 358 | public class CopyCommand : Command 359 | { 360 | public CopyCommand(string name) : base(name) 361 | { 362 | } 363 | } 364 | 365 | public class PasteCommand : Command 366 | { 367 | public PasteCommand(string name) : base(name) 368 | { 369 | } 370 | } 371 | } 372 | 373 | } 374 | -------------------------------------------------------------------------------- /ChurchEncoding/Successor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ploeh.Samples.ChurchEncoding 8 | { 9 | public class Successor : INaturalNumber 10 | { 11 | private readonly INaturalNumber predecessor; 12 | 13 | public Successor(INaturalNumber n) 14 | { 15 | predecessor = n; 16 | } 17 | 18 | public T Accept(INaturalNumberVisitor visitor) 19 | { 20 | return visitor.VisitSucc(predecessor); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ChurchEncoding/Zero.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ploeh.Samples.ChurchEncoding 8 | { 9 | public class Zero : INaturalNumber 10 | { 11 | public T Accept(INaturalNumberVisitor visitor) 12 | { 13 | return visitor.VisitZero; 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /ChurchEncoding/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Mark Seemann 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ChurchEncoding 2 | 3 | Code for the [Church encoding](http://blog.ploeh.dk/2018/05/22/church-encoding) article series, as well as the [Visitor as a sum type](http://blog.ploeh.dk/2018/06/25/visitor-as-a-sum-type) article. 4 | -------------------------------------------------------------------------------- /packages/xunit.2.3.1/xunit.2.3.1.nupkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ploeh/ChurchEncoding/bf1109d22e6cc0831c0f2bbc38a6a27d53391fe3/packages/xunit.2.3.1/xunit.2.3.1.nupkg -------------------------------------------------------------------------------- /packages/xunit.abstractions.2.0.1/lib/net35/xunit.abstractions.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ploeh/ChurchEncoding/bf1109d22e6cc0831c0f2bbc38a6a27d53391fe3/packages/xunit.abstractions.2.0.1/lib/net35/xunit.abstractions.dll -------------------------------------------------------------------------------- /packages/xunit.abstractions.2.0.1/lib/net35/xunit.abstractions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | xunit.abstractions 5 | 6 | 7 | 8 | 9 | Represents source information about a test case. 10 | 11 | 12 | 13 | 14 | Interface implement by objects that want to support serialization in xUnit.net. 15 | 16 | 17 | 18 | 19 | Called when the object should populate itself with data from the serialization info. 20 | 21 | The info to get the data from 22 | 23 | 24 | 25 | Called when the object should store its data into the serialization info. 26 | 27 | The info to store the data in 28 | 29 | 30 | 31 | Gets or sets the source file name. A null value indicates that the 32 | source file name is not known. 33 | 34 | 35 | 36 | 37 | Gets or sets the source file line. A null value indicates that the 38 | source file line is not known. 39 | 40 | 41 | 42 | 43 | Represents a provider which gives source line information for a test case. Generally 44 | consumed by an implementation of during Find operations. 45 | 46 | 47 | 48 | 49 | Returns the source information for a test case. 50 | 51 | The test case to retrieve information for. 52 | The source information, with null string and int values when the information is not available. 53 | Note: return value should never be null, only the interior data values inside. 54 | 55 | 56 | 57 | Represents a test framework. There are two pieces to test frameworks: discovery and 58 | execution. The two factory methods represent these two pieces. Test frameworks can 59 | implement an empty constructor, or they can implement one that takes 60 | if they want to be able to send diagnostic messages. 61 | 62 | 63 | 64 | 65 | Get a test discoverer. 66 | 67 | The assembly from which to discover the tests. 68 | The test discoverer. 69 | 70 | 71 | 72 | Get a test executor. 73 | 74 | The name of the assembly to run tests from. 75 | The test executor. 76 | 77 | 78 | 79 | Sets the source information provider to be used during discovery. 80 | 81 | 82 | 83 | 84 | Represents an implementation of the discovery part of a test framework. 85 | 86 | 87 | 88 | 89 | Starts the process of finding all tests in an assembly. 90 | 91 | Whether to include source file information, if possible. 92 | The message sink to report results back to. 93 | The options used by the test framework during discovery. 94 | 95 | 96 | 97 | Starts the process of finding all tests in a class. 98 | 99 | The fully qualified type name to find tests in. 100 | Whether to include source file information, if possible. 101 | The message sink to report results back to. 102 | The options used by the test framework during discovery. 103 | 104 | 105 | 106 | Serializes a test case into string form. 107 | 108 | The test case to be serialized. 109 | The serialized representation of the test case. 110 | 111 | 112 | 113 | Gets the target framework that the test assembly is linked against. 114 | 115 | 116 | 117 | 118 | Returns the display name of the test framework that this discoverer is running tests for. 119 | 120 | 121 | 122 | 123 | Represents an instance of that is to be used for 124 | test discovery purposes. 125 | 126 | 127 | 128 | 129 | This interface should not be consumed directly; instead, you should 130 | consume 131 | or . 132 | 133 | 134 | 135 | 136 | Gets an option value. 137 | 138 | The type of the value. 139 | The name of the value. 140 | The value. 141 | 142 | 143 | 144 | Sets an option value. 145 | 146 | The type of the value. 147 | The name of the value. 148 | The value to be set. 149 | 150 | 151 | 152 | Represents an instance of that is to be used for 153 | test execution purposes. 154 | 155 | 156 | 157 | 158 | Represents an implementation of the execution part of a test framework. 159 | 160 | 161 | 162 | 163 | De-serializes a test case. 164 | 165 | The string representation of the test case. 166 | The de-serialized test case. 167 | 168 | 169 | 170 | Starts the process of running all the tests in the assembly. 171 | 172 | The message sink to report results back to. 173 | The options to be used during test discovery. 174 | The options to be used during test execution. 175 | 176 | 177 | 178 | Starts the process of running selected tests in the assembly. 179 | 180 | The test cases to run. 181 | The message sink to report results back to. 182 | The options to be used during test execution. 183 | 184 | 185 | 186 | Base message interface for all messages related to test execution. It includes the list 187 | of test cases that are associated with this execution step. 188 | 189 | 190 | 191 | 192 | This is the base interface for all test messages. A test message is a message that is 193 | used to communicate the status of discovery and execution of tests. 194 | 195 | 196 | 197 | 198 | The test cases that are associated with this message. 199 | 200 | 201 | 202 | 203 | This represents failure information for the test runner. It encapsulates multiple sets 204 | of exceptions so that it can provide inner exception information, including support for 205 | . The parent indices indicate the hierarchy of the exceptions 206 | as extracted during the failure; the 0th exception is always the single parent of the tree, 207 | and will have an index of -1. 208 | 209 | 210 | 211 | 212 | The fully-qualified type name of the exceptions. 213 | 214 | 215 | 216 | 217 | The messages of the exceptions. 218 | 219 | 220 | 221 | 222 | The stack traces of the exceptions. 223 | 224 | 225 | 226 | 227 | The parent exception index for the exceptions; a -1 indicates that 228 | the exception in question has no parent. 229 | 230 | 231 | 232 | 233 | This is the base message for various types of completion that can occur during the 234 | various phases of execution process (e.g., test case, test class, test collection, 235 | and assembly). 236 | 237 | 238 | 239 | 240 | The execution time (in seconds) for this execution. 241 | 242 | 243 | 244 | 245 | The number of failing tests. 246 | 247 | 248 | 249 | 250 | The total number of tests run. 251 | 252 | 253 | 254 | 255 | The number of skipped tests. 256 | 257 | 258 | 259 | 260 | Represents an endpoint for the reception of test messages. 261 | 262 | 263 | 264 | 265 | Reports the presence of a message on the message bus. This method should 266 | never throw exceptions. 267 | 268 | The message from the message bus 269 | Return true to continue running tests, or false to stop. 270 | 271 | 272 | 273 | Base message interface for all messages related to test assemblies. 274 | 275 | 276 | 277 | 278 | The test assembly that is associated with this message. 279 | 280 | 281 | 282 | 283 | Base message interface for all messages related to test cases. 284 | 285 | 286 | 287 | 288 | Base message interface for all messages related to test methods. 289 | 290 | 291 | 292 | 293 | Base message interface for all messages related to test classes. 294 | 295 | 296 | 297 | 298 | Base message interface for all messages related to test collections. 299 | 300 | 301 | 302 | 303 | The test collection that is associated with this message. 304 | 305 | 306 | 307 | 308 | The test class that is associated with this message. 309 | 310 | 311 | 312 | 313 | The test method that is associated with this message. 314 | 315 | 316 | 317 | 318 | The test case that is associated with this message. 319 | 320 | 321 | 322 | 323 | Base message interface for all messages related to tests. 324 | 325 | 326 | 327 | 328 | The test that is associated with this message. 329 | 330 | 331 | 332 | 333 | This is the base interface for all individual test results (e.g., tests which 334 | pass, fail, or are skipped). 335 | 336 | 337 | 338 | 339 | The execution time of the test, in seconds. 340 | 341 | 342 | 343 | 344 | The captured output of the test. 345 | 346 | 347 | 348 | 349 | This message is sent during execution to indicate that the After method of 350 | a has completed executing. 351 | 352 | 353 | 354 | 355 | The fully qualified type name of the . 356 | 357 | 358 | 359 | 360 | This message is sent during execution to indicate that the After method of 361 | a is about to execute. 362 | 363 | 364 | 365 | 366 | The fully qualified type name of the . 367 | 368 | 369 | 370 | 371 | This message is sent during execution to indicate that the Before method of 372 | a has completed executing. 373 | 374 | 375 | 376 | 377 | The fully qualified type name of the . 378 | 379 | 380 | 381 | 382 | This message is sent during execution to indicate that the Before method of 383 | a is about to execute. 384 | 385 | 386 | 387 | 388 | The fully qualified type name of the . 389 | 390 | 391 | 392 | 393 | This message is sent when the test framework wants to report a diagnostic message 394 | to the end user. 395 | 396 | 397 | 398 | 399 | Gets the diagnostic message. 400 | 401 | 402 | 403 | 404 | This message indicates that the discovery process has been completed for 405 | the requested assembly. 406 | 407 | 408 | 409 | 410 | This message indicates that an error has occurred in the execution process. 411 | 412 | 413 | 414 | 415 | This message indicates that an error has occurred in test assembly cleanup. 416 | 417 | 418 | 419 | 420 | This message indicates that the execution process has been completed for 421 | the requested assembly. 422 | 423 | 424 | 425 | 426 | This message indicates that the execution process is about to start for 427 | the requested assembly. 428 | 429 | 430 | 431 | 432 | Gets the local date and time when the test assembly execution began. 433 | 434 | 435 | 436 | 437 | Gets a display string that describes the test execution environment. 438 | 439 | 440 | 441 | 442 | Gets a display string which describes the test framework and version number. 443 | 444 | 445 | 446 | 447 | This message indicates that an error has occurred during test case cleanup. 448 | 449 | 450 | 451 | 452 | This message indicates that a test case had been found during the discovery process. 453 | 454 | 455 | 456 | 457 | This message indicates that a test case has finished executing. 458 | 459 | 460 | 461 | 462 | This message indicates that a test case is about to start executing. 463 | 464 | 465 | 466 | 467 | This message indicates that an error has occurred during test class cleanup. 468 | 469 | 470 | 471 | 472 | This message indicates that an instance of a test class has just been constructed. 473 | Instance (non-static) methods of tests get a new instance of the test class for each 474 | individual test execution; static methods do not get an instance of the test class. 475 | 476 | 477 | 478 | 479 | This message indicates that an instance of a test class is about to be constructed. 480 | Instance (non-static) methods of tests get a new instance of the test class for each 481 | individual test execution; static methods do not get an instance of the test class. 482 | 483 | 484 | 485 | 486 | This message indicates that the method was 487 | just called on the test class for the test case that just finished executing. 488 | 489 | 490 | 491 | 492 | This message indicates that the method is 493 | about to be called on the test class for the test case that just finished executing. 494 | 495 | 496 | 497 | 498 | This message indicates that a test class has finished executing (meaning, all of the 499 | test cases in this test class have finished running). 500 | 501 | 502 | 503 | 504 | This message indicates that a test class is about to begin running. 505 | 506 | 507 | 508 | 509 | This message indicates that an error has occurred during test cleanup. 510 | 511 | 512 | 513 | 514 | This message indicates that an error has occurred during test collection cleanup. 515 | 516 | 517 | 518 | 519 | This message indicates that a test collection has just finished executing (meaning, 520 | all the test classes in the collection has finished). 521 | 522 | 523 | 524 | 525 | This message indicates that a test collection has is about to start executing. 526 | 527 | 528 | 529 | 530 | This message indicates that a test has failed. 531 | 532 | 533 | 534 | 535 | This message indicates that a test has finished executing. 536 | 537 | 538 | 539 | 540 | Gets the time spent executing the test, in seconds. 541 | 542 | 543 | 544 | 545 | The captured output of the test. 546 | 547 | 548 | 549 | 550 | This message indicates that an error has occurred during test method cleanup. 551 | 552 | 553 | 554 | 555 | This message indicates that a test method has finished executing (meaning, all 556 | the test cases that derived from the test method have finished). 557 | 558 | 559 | 560 | 561 | This message indicates that a test method is about to begin executing. 562 | 563 | 564 | 565 | 566 | This message indicates that a line of output was provided for a test. 567 | 568 | 569 | 570 | 571 | Gets the line of output. 572 | 573 | 574 | 575 | 576 | Indicates that a test has passed. 577 | 578 | 579 | 580 | 581 | This message indicates that a test was skipped. 582 | 583 | 584 | 585 | 586 | The reason given for skipping the test. 587 | 588 | 589 | 590 | 591 | This message indicates that a test is about to start executing. 592 | 593 | 594 | 595 | 596 | Represents information about an assembly. The primary implementation is based on runtime 597 | reflection, but may also be implemented by runner authors to provide non-reflection-based 598 | test discovery (for example, AST-based runners like CodeRush or Resharper). 599 | 600 | 601 | 602 | 603 | Gets all the custom attributes for the given assembly. 604 | 605 | The type of the attribute, in assembly-qualified form 606 | The matching attributes that decorate the assembly 607 | 608 | 609 | 610 | Gets a for the given type. 611 | 612 | The fully qualified type name. 613 | The if the type exists, or null if not. 614 | 615 | 616 | 617 | Gets all the types for the assembly. 618 | 619 | Set to true to return all types in the assembly, 620 | or false to return only public types. 621 | The types in the assembly. 622 | 623 | 624 | 625 | Gets the on-disk location of the assembly under test. If the assembly path is not 626 | known (for example, in AST-based runners), you must return null. 627 | 628 | 629 | This is used by the test framework wrappers to find the co-located unit test framework 630 | assembly (f.e., xunit.dll or xunit.execution.dll). AST-based runners will need to directly create 631 | instances of and (using the constructors that 632 | support an explicit path to the test framework DLL) rather than relying on the 633 | use of . 634 | 635 | 636 | 637 | 638 | Gets the assembly name. May return a fully qualified name for assemblies found via 639 | reflection (i.e., "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"), 640 | or may return just assembly name only for assemblies found via source code introspection 641 | (i.e., "mscorlib"). 642 | 643 | 644 | 645 | 646 | Represents information about an attribute. The primary implementation is based on runtime 647 | reflection, but may also be implemented by runner authors to provide non-reflection-based 648 | test discovery (for example, AST-based runners like CodeRush or Resharper). 649 | 650 | 651 | 652 | 653 | Gets the arguments passed to the constructor. 654 | 655 | The constructor arguments, in order 656 | 657 | 658 | 659 | Gets all the custom attributes for the given attribute. 660 | 661 | The type of the attribute to find, in assembly-qualified form 662 | The matching attributes that decorate the attribute 663 | 664 | 665 | 666 | Gets a named-argument initialized value of the attribute. If there is no named argument for the given name 667 | on this attribute, then returns default(TValue). 668 | 669 | The type of the argument 670 | The name of the argument 671 | The argument value 672 | 673 | 674 | 675 | Represents information about a method. The primary implementation is based on runtime 676 | reflection, but may also be implemented by runner authors to provide non-reflection-based 677 | test discovery (for example, AST-based runners like CodeRush or Resharper). 678 | 679 | 680 | 681 | 682 | Gets all the custom attributes for the method that are of the given type. 683 | 684 | The type of the attribute, in assembly qualified form 685 | The matching attributes that decorate the method 686 | 687 | 688 | 689 | Gets the types of the generic arguments for generic methods. 690 | 691 | The argument types. 692 | 693 | 694 | 695 | Gets information about the parameters to the method. 696 | 697 | The method's parameters. 698 | 699 | 700 | 701 | Converts an open generic method into a closed generic method, using the provided type arguments. 702 | 703 | The type arguments to be used in the generic definition. 704 | A new that represents the closed generic method. 705 | 706 | 707 | 708 | Gets a value indicating whether the method is abstract. 709 | 710 | 711 | 712 | 713 | Gets a value indicating whether the method is a generic definition (i.e., an open generic). 714 | 715 | 716 | 717 | 718 | Gets a value indicating whether the method is public. 719 | 720 | 721 | 722 | 723 | Gets a value indicating whether the method is static. 724 | 725 | 726 | 727 | 728 | Gets the name of the method. 729 | 730 | 731 | 732 | 733 | Gets the fully qualified type name of the return type. 734 | 735 | 736 | 737 | 738 | Gets a value which represents the class that this method was 739 | reflected from (i.e., equivalent to MethodInfo.ReflectedType) 740 | 741 | 742 | 743 | 744 | Represents information about a method parameter. The primary implementation is based on runtime 745 | reflection, but may also be implemented by runner authors to provide non-reflection-based 746 | test discovery (for example, AST-based runners like CodeRush or Resharper). 747 | 748 | 749 | 750 | 751 | The name of the parameter. 752 | 753 | 754 | 755 | 756 | Gets the type of the parameter. 757 | 758 | 759 | 760 | 761 | Represents a reflection-backed implementation of . 762 | 763 | 764 | 765 | 766 | Gets the underlying for the assembly. 767 | 768 | 769 | 770 | 771 | Represents a reflection-backed implementation of . 772 | 773 | 774 | 775 | 776 | Gets the instance of the attribute, if available. 777 | 778 | 779 | 780 | 781 | Represents a reflection-backed implementation of . 782 | 783 | 784 | 785 | 786 | Gets the underlying for the method. 787 | 788 | 789 | 790 | 791 | Represents a reflection-backed implementation of . 792 | 793 | 794 | 795 | 796 | Gets the underlying for the parameter. 797 | 798 | 799 | 800 | 801 | Represents a reflection-backed implementation of . 802 | 803 | 804 | 805 | 806 | Represents information about a type. The primary implementation is based on runtime 807 | reflection, but may also be implemented by runner authors to provide non-reflection-based 808 | test discovery (for example, AST-based runners like CodeRush or Resharper). 809 | 810 | 811 | 812 | 813 | Gets all the custom attributes for the given type. 814 | 815 | The type of the attribute, in assembly qualified form 816 | The matching attributes that decorate the type 817 | 818 | 819 | 820 | Gets the generic type arguments for a generic type. 821 | 822 | The list of generic types. 823 | 824 | 825 | 826 | Gets a specific method. 827 | 828 | The name of the method. 829 | Set to true to look for the method in both public and private. 830 | The method. 831 | 832 | 833 | 834 | Gets all the methods in this type. 835 | 836 | Set to true to return all methods in the type, 837 | or false to return only public methods. 838 | 839 | 840 | 841 | Gets the assembly this type is located in. 842 | 843 | 844 | 845 | 846 | Gets the base type of the given type. 847 | 848 | 849 | 850 | 851 | Gets the interfaces implemented by the given type. 852 | 853 | 854 | 855 | 856 | Gets a value indicating whether the type is abstract. 857 | 858 | 859 | 860 | 861 | Gets a value indicating whether the type represents a generic parameter. 862 | 863 | 864 | 865 | 866 | Gets a value indicating whether the type is a generic type. 867 | 868 | 869 | 870 | 871 | Gets a value indicating whether the type is sealed. 872 | 873 | 874 | 875 | 876 | Gets a value indicating whether the type is a value type. 877 | 878 | 879 | 880 | 881 | Gets the fully qualified type name (for non-generic parameters), or the 882 | simple type name (for generic parameters). 883 | 884 | 885 | 886 | 887 | Gets the underlying object. 888 | 889 | 890 | 891 | 892 | Represents serialization support in xUnit.net. 893 | 894 | 895 | 896 | 897 | Adds a value to the serialization. Supported value types include the built-in 898 | intrinsics (string, int, long, float, double, and decimal, including nullable 899 | versions of those), any class which implements ), 900 | or arrays of any supported types. 901 | 902 | The key 903 | The value 904 | The optional type of the value 905 | 906 | 907 | 908 | Gets a value from the serialization. 909 | 910 | The key 911 | The type of the value 912 | The value, if present; null, otherwise 913 | 914 | 915 | 916 | Gets a value from the serialization. 917 | 918 | The key 919 | The value, if present; default(T), otherwise 920 | 921 | 922 | 923 | Represents a single test in the system. A test case typically contains only a single test, 924 | but may contain many if circumstances warrant it (for example, test data for a theory cannot 925 | be pre-enumerated, so the theory yields a single test case with multiple tests). 926 | 927 | 928 | 929 | 930 | Gets the display name of the test. 931 | 932 | 933 | 934 | 935 | Gets the test case this test belongs to. 936 | 937 | 938 | 939 | 940 | Represents a test assembly. 941 | 942 | 943 | 944 | 945 | Gets the assembly that this test assembly belongs to. 946 | 947 | 948 | 949 | 950 | Gets the full path of the configuration file name, if one is present. 951 | May be null if there is no configuration file. 952 | 953 | 954 | 955 | 956 | Represents a single test case in the system. This test case usually represents a single test, but in 957 | the case of dynamically generated data for data driven tests, the test case may actually return 958 | multiple results when run. 959 | 960 | 961 | 962 | 963 | Gets the display name of the test case. 964 | 965 | 966 | 967 | 968 | Gets the display text for the reason a test is being skipped; if the test 969 | is not skipped, returns null. 970 | 971 | 972 | 973 | 974 | Get or sets the source file name and line where the test is defined, if requested (and known). 975 | 976 | 977 | 978 | 979 | Gets the test method this test case belongs to. 980 | 981 | 982 | 983 | 984 | Gets the arguments that will be passed to the test method. 985 | 986 | 987 | 988 | 989 | Gets the trait values associated with this test case. If 990 | there are none, or the framework does not support traits, 991 | this should return an empty dictionary (not null). This 992 | dictionary must be treated as read-only. 993 | 994 | 995 | 996 | 997 | Gets a unique identifier for the test case. 998 | 999 | 1000 | The unique identifier for a test case should be able to discriminate 1001 | among test cases, even those which are varied invocations against the 1002 | same test method (i.e., theories). Ideally, this identifier would remain 1003 | stable until such time as the developer changes some fundamental part 1004 | of the identity (assembly, class name, test name, or test data); however, 1005 | the minimum stability of the identifier must at least extend across 1006 | multiple discoveries of the same test in the same (non-recompiled) 1007 | assembly. 1008 | 1009 | 1010 | 1011 | 1012 | Represents a test class. 1013 | 1014 | 1015 | 1016 | 1017 | Gets the class that this test case is attached to. 1018 | 1019 | 1020 | 1021 | 1022 | Gets the test collection this test case belongs to. 1023 | 1024 | 1025 | 1026 | 1027 | Represents a group of test cases. Test collections form the basis of the parallelization in 1028 | xUnit.net. Test cases which are in the same test collection will not be run in parallel 1029 | against sibling tests, but will run in parallel against tests in other collections. 1030 | 1031 | 1032 | 1033 | 1034 | Gets the type that the test collection was defined with, if available; may be null 1035 | if the test collection didn't have a definition type. 1036 | 1037 | 1038 | 1039 | 1040 | Gets the display name of the test collection. 1041 | 1042 | 1043 | 1044 | 1045 | Gets the test assembly this test collection belongs to. 1046 | 1047 | 1048 | 1049 | 1050 | Gets the test collection ID. Test collection equality is determined by comparing IDs. 1051 | 1052 | 1053 | 1054 | 1055 | Represents a test method. 1056 | 1057 | 1058 | 1059 | 1060 | Gets the method associated with this test method. 1061 | 1062 | 1063 | 1064 | 1065 | Gets the test class that this test method belongs to. 1066 | 1067 | 1068 | 1069 | 1070 | Represents a class which can be used to provide test output. 1071 | 1072 | 1073 | 1074 | 1075 | Adds a line of text to the output. 1076 | 1077 | The message 1078 | 1079 | 1080 | 1081 | Formats a line of text and adds it to the output. 1082 | 1083 | The message format 1084 | The format arguments 1085 | 1086 | 1087 | 1088 | -------------------------------------------------------------------------------- /packages/xunit.abstractions.2.0.1/lib/netstandard1.0/xunit.abstractions.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ploeh/ChurchEncoding/bf1109d22e6cc0831c0f2bbc38a6a27d53391fe3/packages/xunit.abstractions.2.0.1/lib/netstandard1.0/xunit.abstractions.dll -------------------------------------------------------------------------------- /packages/xunit.abstractions.2.0.1/xunit.abstractions.2.0.1.nupkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ploeh/ChurchEncoding/bf1109d22e6cc0831c0f2bbc38a6a27d53391fe3/packages/xunit.abstractions.2.0.1/xunit.abstractions.2.0.1.nupkg -------------------------------------------------------------------------------- /packages/xunit.analyzers.0.7.0/analyzers/dotnet/cs/xunit.analyzers.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ploeh/ChurchEncoding/bf1109d22e6cc0831c0f2bbc38a6a27d53391fe3/packages/xunit.analyzers.0.7.0/analyzers/dotnet/cs/xunit.analyzers.dll -------------------------------------------------------------------------------- /packages/xunit.analyzers.0.7.0/tools/install.ps1: -------------------------------------------------------------------------------- 1 | param($installPath, $toolsPath, $package, $project) 2 | 3 | if($project.Object.SupportsPackageDependencyResolution) 4 | { 5 | if($project.Object.SupportsPackageDependencyResolution()) 6 | { 7 | # Do not install analyzers via install.ps1, instead let the project system handle it. 8 | return 9 | } 10 | } 11 | 12 | $analyzersPaths = Join-Path (Join-Path (Split-Path -Path $toolsPath -Parent) "analyzers") * -Resolve 13 | 14 | foreach($analyzersPath in $analyzersPaths) 15 | { 16 | if (Test-Path $analyzersPath) 17 | { 18 | # Install the language agnostic analyzers. 19 | foreach ($analyzerFilePath in Get-ChildItem -Path "$analyzersPath\*.dll" -Exclude *.resources.dll) 20 | { 21 | if($project.Object.AnalyzerReferences) 22 | { 23 | $project.Object.AnalyzerReferences.Add($analyzerFilePath.FullName) 24 | } 25 | } 26 | } 27 | } 28 | 29 | # $project.Type gives the language name like (C# or VB.NET) 30 | $languageFolder = "" 31 | if($project.Type -eq "C#") 32 | { 33 | $languageFolder = "cs" 34 | } 35 | if($project.Type -eq "VB.NET") 36 | { 37 | $languageFolder = "vb" 38 | } 39 | if($languageFolder -eq "") 40 | { 41 | return 42 | } 43 | 44 | foreach($analyzersPath in $analyzersPaths) 45 | { 46 | # Install language specific analyzers. 47 | $languageAnalyzersPath = join-path $analyzersPath $languageFolder 48 | if (Test-Path $languageAnalyzersPath) 49 | { 50 | foreach ($analyzerFilePath in Get-ChildItem -Path "$languageAnalyzersPath\*.dll" -Exclude *.resources.dll) 51 | { 52 | if($project.Object.AnalyzerReferences) 53 | { 54 | $project.Object.AnalyzerReferences.Add($analyzerFilePath.FullName) 55 | } 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /packages/xunit.analyzers.0.7.0/tools/uninstall.ps1: -------------------------------------------------------------------------------- 1 | param($installPath, $toolsPath, $package, $project) 2 | 3 | if($project.Object.SupportsPackageDependencyResolution) 4 | { 5 | if($project.Object.SupportsPackageDependencyResolution()) 6 | { 7 | # Do not uninstall analyzers via uninstall.ps1, instead let the project system handle it. 8 | return 9 | } 10 | } 11 | 12 | $analyzersPaths = Join-Path (Join-Path (Split-Path -Path $toolsPath -Parent) "analyzers") * -Resolve 13 | 14 | foreach($analyzersPath in $analyzersPaths) 15 | { 16 | # Uninstall the language agnostic analyzers. 17 | if (Test-Path $analyzersPath) 18 | { 19 | foreach ($analyzerFilePath in Get-ChildItem -Path "$analyzersPath\*.dll" -Exclude *.resources.dll) 20 | { 21 | if($project.Object.AnalyzerReferences) 22 | { 23 | $project.Object.AnalyzerReferences.Remove($analyzerFilePath.FullName) 24 | } 25 | } 26 | } 27 | } 28 | 29 | # $project.Type gives the language name like (C# or VB.NET) 30 | $languageFolder = "" 31 | if($project.Type -eq "C#") 32 | { 33 | $languageFolder = "cs" 34 | } 35 | if($project.Type -eq "VB.NET") 36 | { 37 | $languageFolder = "vb" 38 | } 39 | if($languageFolder -eq "") 40 | { 41 | return 42 | } 43 | 44 | foreach($analyzersPath in $analyzersPaths) 45 | { 46 | # Uninstall language specific analyzers. 47 | $languageAnalyzersPath = join-path $analyzersPath $languageFolder 48 | if (Test-Path $languageAnalyzersPath) 49 | { 50 | foreach ($analyzerFilePath in Get-ChildItem -Path "$languageAnalyzersPath\*.dll" -Exclude *.resources.dll) 51 | { 52 | if($project.Object.AnalyzerReferences) 53 | { 54 | try 55 | { 56 | $project.Object.AnalyzerReferences.Remove($analyzerFilePath.FullName) 57 | } 58 | catch 59 | { 60 | 61 | } 62 | } 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /packages/xunit.analyzers.0.7.0/xunit.analyzers.0.7.0.nupkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ploeh/ChurchEncoding/bf1109d22e6cc0831c0f2bbc38a6a27d53391fe3/packages/xunit.analyzers.0.7.0/xunit.analyzers.0.7.0.nupkg -------------------------------------------------------------------------------- /packages/xunit.assert.2.3.1/lib/netstandard1.1/xunit.assert.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ploeh/ChurchEncoding/bf1109d22e6cc0831c0f2bbc38a6a27d53391fe3/packages/xunit.assert.2.3.1/lib/netstandard1.1/xunit.assert.dll -------------------------------------------------------------------------------- /packages/xunit.assert.2.3.1/xunit.assert.2.3.1.nupkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ploeh/ChurchEncoding/bf1109d22e6cc0831c0f2bbc38a6a27d53391fe3/packages/xunit.assert.2.3.1/xunit.assert.2.3.1.nupkg -------------------------------------------------------------------------------- /packages/xunit.core.2.3.1/build/xunit.core.props: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | true 10 | true 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /packages/xunit.core.2.3.1/build/xunit.core.targets: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | true 7 | full 8 | true 9 | 10 | 11 | 12 | 13 | portable 14 | true 15 | true 16 | 17 | 18 | 19 | 20 | full 21 | 22 | 23 | 24 | xunit.execution.desktop.dll 25 | PreserveNewest 26 | False 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /packages/xunit.core.2.3.1/build/xunit.execution.desktop.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ploeh/ChurchEncoding/bf1109d22e6cc0831c0f2bbc38a6a27d53391fe3/packages/xunit.core.2.3.1/build/xunit.execution.desktop.dll -------------------------------------------------------------------------------- /packages/xunit.core.2.3.1/buildMultiTargeting/xunit.core.props: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | true 10 | true 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /packages/xunit.core.2.3.1/buildMultiTargeting/xunit.core.targets: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | true 7 | full 8 | true 9 | 10 | 11 | 12 | 13 | portable 14 | true 15 | true 16 | 17 | 18 | 19 | 20 | full 21 | 22 | 23 | 24 | xunit.execution.desktop.dll 25 | PreserveNewest 26 | False 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /packages/xunit.core.2.3.1/xunit.core.2.3.1.nupkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ploeh/ChurchEncoding/bf1109d22e6cc0831c0f2bbc38a6a27d53391fe3/packages/xunit.core.2.3.1/xunit.core.2.3.1.nupkg -------------------------------------------------------------------------------- /packages/xunit.extensibility.core.2.3.1/lib/netstandard1.1/xunit.core.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ploeh/ChurchEncoding/bf1109d22e6cc0831c0f2bbc38a6a27d53391fe3/packages/xunit.extensibility.core.2.3.1/lib/netstandard1.1/xunit.core.dll -------------------------------------------------------------------------------- /packages/xunit.extensibility.core.2.3.1/lib/netstandard1.1/xunit.core.dll.tdnet: -------------------------------------------------------------------------------- 1 | 2 | xUnit.net {0}.{1}.{2} build {3} 3 | xunit.runner.tdnet.dll 4 | Xunit.Runner.TdNet.TdNetRunner 5 | -------------------------------------------------------------------------------- /packages/xunit.extensibility.core.2.3.1/lib/netstandard1.1/xunit.runner.tdnet.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ploeh/ChurchEncoding/bf1109d22e6cc0831c0f2bbc38a6a27d53391fe3/packages/xunit.extensibility.core.2.3.1/lib/netstandard1.1/xunit.runner.tdnet.dll -------------------------------------------------------------------------------- /packages/xunit.extensibility.core.2.3.1/lib/netstandard1.1/xunit.runner.utility.net452.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ploeh/ChurchEncoding/bf1109d22e6cc0831c0f2bbc38a6a27d53391fe3/packages/xunit.extensibility.core.2.3.1/lib/netstandard1.1/xunit.runner.utility.net452.dll -------------------------------------------------------------------------------- /packages/xunit.extensibility.core.2.3.1/xunit.extensibility.core.2.3.1.nupkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ploeh/ChurchEncoding/bf1109d22e6cc0831c0f2bbc38a6a27d53391fe3/packages/xunit.extensibility.core.2.3.1/xunit.extensibility.core.2.3.1.nupkg -------------------------------------------------------------------------------- /packages/xunit.extensibility.execution.2.3.1/lib/net452/xunit.execution.desktop.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ploeh/ChurchEncoding/bf1109d22e6cc0831c0f2bbc38a6a27d53391fe3/packages/xunit.extensibility.execution.2.3.1/lib/net452/xunit.execution.desktop.dll -------------------------------------------------------------------------------- /packages/xunit.extensibility.execution.2.3.1/lib/netstandard1.1/xunit.execution.dotnet.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ploeh/ChurchEncoding/bf1109d22e6cc0831c0f2bbc38a6a27d53391fe3/packages/xunit.extensibility.execution.2.3.1/lib/netstandard1.1/xunit.execution.dotnet.dll -------------------------------------------------------------------------------- /packages/xunit.extensibility.execution.2.3.1/xunit.extensibility.execution.2.3.1.nupkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ploeh/ChurchEncoding/bf1109d22e6cc0831c0f2bbc38a6a27d53391fe3/packages/xunit.extensibility.execution.2.3.1/xunit.extensibility.execution.2.3.1.nupkg --------------------------------------------------------------------------------