Skip to content

Instantly share code, notes, and snippets.

@ritalin
Created July 4, 2012 10:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ritalin/3046512 to your computer and use it in GitHub Desktop.
Save ritalin/3046512 to your computer and use it in GitHub Desktop.
Maybeモナドの写経
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);
}
}
}
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;
}
}
}
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