Created
July 4, 2012 10:06
-
-
Save ritalin/3046512 to your computer and use it in GitHub Desktop.
Maybeモナドの写経
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
using System.Threading.Tasks; | |
using NUnit.Framework; | |
namespace Common.Test { | |
public static class AssertRequiedExtensions { | |
public static Maybe<TValue> FailUnless<TValue>(this Maybe<TValue> inValue, Func<TValue, bool> inAcceptedFunc, string inFailedMessage) { | |
var val = MaybeExtensons.NothingUnless(inValue, inAcceptedFunc); | |
if (val == Maybe<TValue>.Nothing) { | |
Assert.Fail(inFailedMessage); | |
} | |
return val; | |
} | |
public static Maybe<TValue> FailIfNull<TValue>(this Maybe<TValue> inValue, string inFailedMessage) { | |
return FailUnless(inValue, (v) => v != null, inFailedMessage); | |
} | |
} | |
public static class AssertRequiedAsyncExtensions { | |
public static async Task<Maybe<TValue>> FailUnlessAsync<TValue>(this Task<Maybe<TValue>> inValue, Func<TValue, Task<bool>> inAcceptedFunc, string inFailedMessage) { | |
var val = await MaybeAsyncExtensons.NothingUnlessAsync(await inValue, inAcceptedFunc); | |
if (val == Maybe<TValue>.Nothing) { | |
Assert.Fail(inFailedMessage); | |
} | |
return val; | |
} | |
public static async Task<Maybe<TValue>> FailUnlessAsync<TValue>(this Task<Maybe<TValue>> inValue, Func<TValue, bool> inAcceptedFunc, string inFailedMessage) { | |
var val = MaybeExtensons.NothingUnless(await inValue, inAcceptedFunc); | |
if (val == Maybe<TValue>.Nothing) { | |
Assert.Fail(inFailedMessage); | |
} | |
return val; | |
} | |
public static async Task<Maybe<TValue>> FailIfNullAsync<TValue>(this Task<Maybe<TValue>> inTask, string inFailedMessage) { | |
return AssertRequiedExtensions.FailIfNull(await inTask, inFailedMessage); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
using System.Threading.Tasks; | |
namespace Common.Test { | |
public class Maybe<TValue> { | |
public static readonly Maybe<TValue> Nothing = new Maybe<TValue>(); | |
public Maybe(TValue inValue) { | |
this.Value = inValue; | |
} | |
private Maybe() { } | |
public TValue Value { get; private set; } | |
} | |
public static class Maybe { | |
public static Maybe<TValue> ToMaybe<TValue>(this TValue inValue) { | |
return new Maybe<TValue>(inValue); | |
} | |
public static Maybe<TValue> ToMaybe<TValue>(Func<TValue> inFunc) { | |
return inFunc().ToMaybe(); | |
} | |
public static async Task<Maybe<TValue>> ToMaybe<TValue>(Func<Task<TValue>> inFunc) { | |
var value = await inFunc(); | |
return value.ToMaybe(); | |
} | |
} | |
public static class MaybeExtensons { | |
public static Maybe<TValue> NothingUnless<TValue>(this Maybe<TValue> inValue, Func<TValue, bool> inAcceptedFunc) { | |
return inAcceptedFunc(inValue.Value) ? inValue : Maybe<TValue>.Nothing; | |
} | |
public static Maybe<TValue> NothingIfNull<TValue>(this Maybe<TValue> inValue) { | |
return inValue.NothingUnless((v) => v != null); | |
} | |
public static Maybe<TResult> Select<TSource, TResult>(this Maybe<TSource> inSource, Func<TSource, TResult> inResultSelectorFunc) { | |
return SelectCore(inSource, s => inResultSelectorFunc(s)); | |
} | |
public static Maybe<TResult> SelectMany<TSource, TResult>( | |
this Maybe<TSource> inSource, | |
Func<TSource, Maybe<TResult>> inSelectorFunc) | |
{ | |
return SelectMany(inSource, inSelectorFunc, (s, t) => t); | |
} | |
public static Maybe<TResult> SelectMany<TSource, TTemporary, TResult>( | |
this Maybe<TSource> inSource, | |
Func<TSource, Maybe<TTemporary>> inSelectorFunc, | |
Func<TSource, TTemporary, TResult> inResultSelector) | |
{ | |
return Maybe<TSource>.Nothing != inSource ? Select(inSource, s => inSelectorFunc(s).Select(t => inResultSelector(s, t))).Value : Maybe<TResult>.Nothing; | |
} | |
private static Maybe<TResult> SelectCore<TSource, TResult>(Maybe<TSource> inSource, Func<TSource, TResult> inSelectorFunc) { | |
if (Maybe<TSource>.Nothing == inSource) { | |
return Maybe<TResult>.Nothing; | |
} | |
else { | |
return inSelectorFunc(inSource.Value).ToMaybe(); | |
} | |
} | |
} | |
public static class MaybeAsyncExtensons { | |
public static async Task<Maybe<TValue>> NothingUnlessAsync<TValue>(this Maybe<TValue> inValue, Func<TValue, Task<bool>> inAcceptedFunc) { | |
return await inAcceptedFunc(inValue.Value) ? inValue : Maybe<TValue>.Nothing; | |
} | |
public static async Task<Maybe<TValue>> NothingUnlessAsync<TValue>(this Task<Maybe<TValue>> inValue, Func<TValue, Task<bool>> inAcceptedFunc) { | |
return await NothingUnlessAsync(await inValue, inAcceptedFunc); | |
} | |
public static async Task<Maybe<TValue>> NothingUnlessAsync<TValue>(this Task<Maybe<TValue>> inValue, Func<TValue, bool> inAcceptedFunc) { | |
return MaybeExtensons.NothingUnless(await inValue, inAcceptedFunc); | |
} | |
public static async Task<Maybe<TValue>> NothingIfNullAsync<TValue>(this Task<Maybe<TValue>> inValue) { | |
return MaybeExtensons.NothingUnless(await inValue, (v) => v != null); | |
} | |
public static async Task<Maybe<TResult>> Select<TSource, TResult>(this Maybe<TSource> inSource, Func<TSource, Task<TResult>> inResultSelectorFunc) { | |
var result = MaybeExtensons.Select(inSource, s => inResultSelectorFunc(s)); | |
return Maybe<Task<TResult>>.Nothing != result ? (await result.Value).ToMaybe() : Maybe<TResult>.Nothing; | |
} | |
public static async Task<Maybe<TResult>> Select<TSource, TResult>(this Task<Maybe<TSource>> inSource, Func<TSource, Task<TResult>> inResultSelectorFunc) { | |
return await Select(await inSource, inResultSelectorFunc); | |
} | |
public static async Task<Maybe<TResult>> Select<TSource, TResult>(this Task<Maybe<TSource>> inSource, Func<TSource, TResult> inResultSelectorFunc) { | |
return MaybeExtensons.Select(await inSource, s => inResultSelectorFunc(s)); | |
} | |
public static async Task<Maybe<TResult>> SelectMany<TSource, TResult>(this Task<Maybe<TSource>> inSource, Func<TSource, Task<Maybe<TResult>>> inSelectorFunc) { | |
return await SelectManyCore( | |
await inSource, | |
(s) => inSelectorFunc(s).ToMaybe(), | |
(s, t) => t | |
); | |
} | |
public static async Task<Maybe<TResult>> SelectMany<TSource, TTemporary, TResult>( | |
this Task<Maybe<TSource>> inSource, | |
Func<TSource, Task<Maybe<TTemporary>>> inSelectorFunc, | |
Func<TSource, TTemporary, TResult> inResultSelector) | |
{ | |
return await SelectManyCore( | |
await inSource, | |
(s) => inSelectorFunc(s).ToMaybe(), | |
inResultSelector | |
); | |
} | |
public static async Task<Maybe<TResult>> SelectMany<TSource, TResult>(this Maybe<TSource> inSource, Func<TSource, Task<Maybe<TResult>>> inSelectorFunc) { | |
return await SelectManyCore( | |
inSource, | |
(s) => inSelectorFunc(s).ToMaybe(), | |
(s, t) => t | |
); | |
} | |
private static async Task<Maybe<TResult>> SelectManyCore<TSource, TTemporary, TResult>( | |
Maybe<TSource> inSource, | |
Func<TSource, Maybe<Task<Maybe<TTemporary>>>> inSelectorFunc, | |
Func<TSource, TTemporary, TResult> inResultSelector) | |
{ | |
var result = MaybeExtensons.SelectMany( | |
inSource, | |
inSelectorFunc, | |
async (s, t) => inResultSelector(s, (await t).Value) | |
); | |
return Maybe<Task<TResult>>.Nothing != result ? (await (result.Value)).ToMaybe() : Maybe<TResult>.Nothing; | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
using System.Threading.Tasks; | |
using NUnit.Framework; | |
namespace Common.Test { | |
[TestFixture] | |
public class MaybeTest { | |
[Test] | |
public void _正常系の計算_クエリ式() { | |
var result = | |
from x in 10.ToMaybe() | |
from y in 20.ToMaybe() | |
from z in 30.ToMaybe() | |
select x + y + z | |
; | |
Assert.That(result, Is.Not.SameAs(Maybe<int>.Nothing), "Nothingではない"); | |
Assert.That(result.Value, Is.EqualTo(60), "計算結果が入っている"); | |
} | |
[Test] | |
public void _異常系の計算_1_クエリ式() { | |
var result = | |
from x in Maybe<int>.Nothing | |
from y in 20.ToMaybe() | |
from z in 10.ToMaybe() | |
select x + y + z | |
; | |
Assert.That(result, Is.EqualTo(Maybe<int>.Nothing), "Nothingになる"); | |
} | |
[Test] | |
public void _異常系の計算_2_クエリ式() { | |
var result = | |
from x in 15.ToMaybe() | |
from y in Maybe<int>.Nothing | |
from z in 20.ToMaybe() | |
select x + y | |
; | |
Assert.That(result, Is.SameAs(Maybe<int>.Nothing), "Nothingになる"); | |
} | |
[Test] | |
public void _異常系の計算_3_クエリ式() { | |
var result = | |
from x in 15.ToMaybe() | |
from y in 20.ToMaybe() | |
from z in Maybe<int>.Nothing | |
select x + y | |
; | |
Assert.That(result, Is.SameAs(Maybe<int>.Nothing), "Nothingになる"); | |
} | |
[Test] | |
[Description("この展開は可能性が低く")] | |
public void _正常系の計算_1_メソッド式() { | |
var result = 16.ToMaybe().SelectMany(x => | |
32.ToMaybe().SelectMany(y => | |
64.ToMaybe().SelectMany(z => | |
(x + y + z).ToMaybe() | |
) | |
) | |
); | |
Assert.That(result, Is.Not.SameAs(Maybe<int>.Nothing), "Nothingではない"); | |
Assert.That(result.Value, Is.EqualTo(112), "計算結果が入っている"); | |
} | |
[Test] | |
[Description("こう展開されると思っていた")] | |
public void _正常系の計算_2_メソッド式() { | |
var result = 11.ToMaybe().SelectMany(x => | |
33.ToMaybe().SelectMany( | |
y => 55.ToMaybe(), | |
(y, z) => x + y + z | |
) | |
); | |
Assert.That(result, Is.Not.SameAs(Maybe<int>.Nothing), "Nothingではない"); | |
Assert.That(result.Value, Is.EqualTo(99), "計算結果が入っている"); | |
} | |
[Test] | |
[Description("こう来るとは思わなかった")] | |
public void _正常系の計算_3_メソッド式() { | |
var result = 100.ToMaybe() | |
.SelectMany( | |
x => 150.ToMaybe(), | |
(s, t) => new { x = s, y = t } | |
) | |
.SelectMany( | |
anon => 200.ToMaybe(), | |
(s, t) => s.x + s.y + t | |
) | |
; | |
Assert.That(result, Is.Not.SameAs(Maybe<int>.Nothing), "Nothingではない"); | |
Assert.That(result.Value, Is.EqualTo(450), "計算結果が入っている"); | |
} | |
[Test] | |
public void _異常系の計算_1A_メソッド式() { | |
var result = Maybe<int>.Nothing.SelectMany(x => | |
20.ToMaybe().SelectMany(y => | |
(x + y).ToMaybe() | |
) | |
); | |
Assert.That(result, Is.SameAs(Maybe<int>.Nothing), "Nothingになる"); | |
} | |
[Test] | |
public void _異常系の計算_1B_メソッド式() { | |
var result = Maybe<int>.Nothing.SelectMany( | |
x => 99.ToMaybe(), | |
(x, y) => x + y | |
); | |
Assert.That(result, Is.SameAs(Maybe<int>.Nothing), "Nothingになる"); | |
} | |
[Test] | |
public void _異常系の計算_2A_メソッド式() { | |
var result = 15.ToMaybe().SelectMany(x => | |
Maybe<int>.Nothing.SelectMany(y => | |
(x + y).ToMaybe() | |
) | |
); | |
Assert.That(result, Is.SameAs(Maybe<int>.Nothing), "Nothingになる"); | |
} | |
[Test] | |
public void _異常系の計算_2B_メソッド式() { | |
var result = 15.ToMaybe().SelectMany(x => | |
Maybe<int>.Nothing.Select(y => | |
x + y | |
) | |
); | |
Assert.That(result, Is.SameAs(Maybe<int>.Nothing), "Nothingになる"); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment