gpt4 book ai didi

c# - Bind 和 Map 之外的 Option monad 的标准操作

转载 作者:太空狗 更新时间:2023-10-30 00:03:11 26 4
gpt4 key购买 nike

我正在使用 F# 的 C# 实现 option<`a`> Petricek 书中的 monad(真实世界函数式编程):

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# documentation ,它给了我关于要添加的其他一些有用的扩展方法的提示,但不完全是我需要的。

我设计这个函数来满足我的需要:

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> 上的操作?单子(monad)? 按需添加新操作是否正确?

最佳答案

您始终可以提取值的 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) { ... }

或者,您可以从中创建一个 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) { ... }

这两个表征是等价的;您可以构建一个给定的另一个实现。

一个comonad有操作

static T Extract<T>(M<T> mt) { ... } 
static M<R> Extend<A, R>(M<A> ma, Func<M<A>, R> func) { ... }

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) { ... }

其中 Duplicate 是 Join 的“对立面”。同样,这两个特征是等价的;给定一个,您可以构建另一个。

很明显,您不能仅在给定 Bind、Unit、FMap 和 Join 的情况下实现 Extract,因为这些都不会以任何方式返回 T,而这是您需要的 T。

对于任一版本的 comonad,您遇到的问题是可选的 monad 实际上不是 comonad,因为如果 monadic 值“缺失”,则没有自然的方法来实现 Extract。

现在,你可以做什么Nullable<T>如果你愿意的话。 Nullable<T>.GetValueOrDefault()如果存在 1 和 default(T),则返回值如果没有。如果您想将 Optional 变成一个 comonad,这可能是您在这里可以做的最好的事情。

关于c# - Bind 和 Map 之外的 Option<T> monad 的标准操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15955248/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com