option<`a`>
Petricek book (Real World Functional Programming)の F# モナドの C# 実装を使用しています。
internal enum OptionType { Some, None }
internal abstract class Option<T>
{
private readonly OptionType tag;
protected Option(OptionType tag)
{
this.tag = tag;
}
public OptionType Tag
{
get { return this.tag; }
}
public bool MatchNone()
{
return this.Tag == OptionType.None;
}
public bool MatchSome(out T value)
{
if (this.Tag == OptionType.Some)
{
value = ((Some<T>)this).Value;
}
else
{
value = default(T);
}
return this.Tag == OptionType.Some;
}
}
internal sealed class None<T> : Option<T>
{
public None() : base(OptionType.None) { }
}
internal sealed class Some<T> : Option<T>
{
private readonly T value;
public Some(T value)
: base(OptionType.Some)
{
this.value = value;
}
public T Value
{
get
{
return this.value;
}
}
}
internal static class Option
{
public static Option<T> None<T>()
{
return new None<T>();
}
public static Some<T> Some<T>(T value)
{
return new Some<T>(value);
}
}
internal static class OptionExtensions
{
public static Option<T2> Bind<T1, T2>(this Option<T1> option, Func<T1, Option<T2>> func)
{
T1 value1;
if (option.MatchSome(out value1))
{
return func(value1);
}
return Option.None<T2>();
}
public static Option<T2> Map<T1, T2>(this Option<T1> option, Func<T1, T2> func)
{
T1 value1;
if (option.MatchSome(out value1))
{
return Option.Some(func(value1));
}
return Option.None<T2>();
}
}
None
値がデフォルトでない場合、またはデフォルトを返す場合は、値を抽出する操作が必要です。
Map
との組み合わせでこれが可能かどうか疑問に思ってBind
いましたが、そうではないと思います。
F# のドキュメントに戻って、追加すべき他の便利な拡張メソッドについてのヒントを得ることができましたが、正確には必要なものではありませんでした。
私は自分のニーズを満たすためにこの関数を設計しました:
public static T2 Return<T1, T2>(this Option<T1> option, Func<T1, T2> func, T2 noneValue)
{
T1 value1;
if (option.MatchSome(out value1))
{
return func(value1);
}
return noneValue;
}
車輪の再発明を避けるために、質問は:Option<T>
モナドの操作を定義するための参照または共通の関数パターンはありますか? 必要に応じて新しい操作を追加するのは正しいですか?