private static IExpectation <Response <T>, IExpectedResponse <M> > Responding <T, M>(IExpectation <T, M> resultMeta) { var tagMeta = Exact <Response>(EqualityComparer <Response> .Default); var errorMeta = Trivial(); return(new Expectation <Response <T>, IExpectedResponse <M> >( unknownF: () => new ExpectedResponse <M>( onTag: tagMeta.Unknown(), onError: errorMeta.Unknown().Some(), onResult: resultMeta.Unknown().Some()), definiteF: response => { switch (response.Tag) { case Response.Failure: return new ExpectedResponse <M>( onTag: tagMeta.Definite(response.Tag), onError: errorMeta.Definite(Unit.Singleton).Some(), onResult: new Option <M> .None()); case Response.Success: var success = (Response <T> .Success)response; return new ExpectedResponse <M>( onTag: tagMeta.Definite(response.Tag), onError: new Option <Unit> .None(), onResult: resultMeta.Definite(success.Result).Some()); default: throw new ArgumentOutOfRangeException(); } }, unionF: (left, right) => { var onTag = tagMeta.Union(left.OnTag, right.OnTag); var onFailure = left.OnError.Merge(right.OnError, errorMeta.Union); var onSuccess = left.OnResult.Merge(right.OnResult, resultMeta.Union); return new ExpectedResponse <M>( onTag: onTag, onError: onFailure, onResult: onSuccess); }, extensionF: meta => { return new Set <Response <T> >( containsF: response => { if (tagMeta.Extension(meta.OnTag).Contains(response.Tag)) { switch (response.Tag) { case Response.Failure: return errorMeta.Extension(meta.OnError.Get()).Contains(Unit.Singleton); case Response.Success: var success = (Response <T> .Success)response; return resultMeta.Extension(meta.OnResult.Get()).Contains(success.Result); default: throw new ArgumentOutOfRangeException(); } } return false; }); })); }