jay*_*jay 4 c# monads functional-programming
我正在使用option<`a`>Petricek出版的F#monad 的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>();
}
}
Run Code Online (Sandbox Code Playgroud)
现在我需要一个操作来提取值,如果它不是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;
}
Run Code Online (Sandbox Code Playgroud)
因此,为了不重新发明轮子,问题是:是否有一个参考或常用的功能模式来定义Option<T>monad上的操作?是否正确添加需要的新操作?
Eri*_*ert 15
您可以随时提取值的monad通常是comonad.你知道monad M<T>有方法(用C#语法)
static M<T> Unit<T>(T t) { ... }
static M<R> Bind<A, R>(M<A> ma, Func<A, M<R>> func) { ... }
Run Code Online (Sandbox Code Playgroud)
或者,您也可以制作一个monad
static M<T> Unit<T>(T t) { ... }
static M<R> FMap<A, R>(M<A> ma, Func<A, R> func) { ... }
static M<T> Join<T>(M<M<T>> mmt) { ... }
Run Code Online (Sandbox Code Playgroud)
这两个特征是等价的; 你可以构建另一个给定的实现.
comonad有操作
static T Extract<T>(M<T> mt) { ... }
static M<R> Extend<A, R>(M<A> ma, Func<M<A>, R> func) { ... }
Run Code Online (Sandbox Code Playgroud)
Extract是Unit的"对立面",而Extend是Bind的"对立面".
或者,您也可以使用以下操作定义comonad:
static T Extract<T>(M<T> mt) { ... }
static M<R> FMap<A, R>(M<A> ma, Func<A, R> func) { ... }
static M<M<T>> Duplicate<T>(M<T> mt) { ... }
Run Code Online (Sandbox Code Playgroud)
其中Duplicate是Join的"对立面".同样,这两个特征是等价的; 给定一个,你可以建立另一个.
很明显,只有给定Bind,Unit,FMap和Join才能实现Extract,因为这些都不会以任何方式返回 T,而是它需要的T.
对于任一版本的comonads,您遇到的问题是可选的monad确实不是comonad,因为如果monadic值"缺失",则没有自然的方法来实现Extract.
现在,你可以做Nullable<T>你想做的事情.Nullable<T>.GetValueOrDefault()如果有值,则返回值,如果没有则返回值default(T).如果你想在一个comonad中选择Optional,那么这可能是你在这里做的最好的.
| 归档时间: |
|
| 查看次数: |
1861 次 |
| 最近记录: |