调整Option
This commit is contained in:
parent
59f4e8c110
commit
8b4aae1d63
|
@ -0,0 +1,13 @@
|
||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Rider ignored files
|
||||||
|
/contentModel.xml
|
||||||
|
/projectSettingsUpdater.xml
|
||||||
|
/modules.xml
|
||||||
|
/.idea.Sanchime.iml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
|
@ -0,0 +1 @@
|
||||||
|
Sanchime
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
|
||||||
|
</project>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="UserContentModel">
|
||||||
|
<attachedFolders />
|
||||||
|
<explicitIncludes />
|
||||||
|
<explicitExcludes />
|
||||||
|
</component>
|
||||||
|
</project>
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
|
@ -6,5 +6,5 @@ namespace Sanchime.Functional.Extensions;
|
||||||
public static class DictionaryExtension
|
public static class DictionaryExtension
|
||||||
{
|
{
|
||||||
public static Option<T> Lookup<K, T>(this Dictionary<K, T> dictionary, K key) where K: notnull
|
public static Option<T> Lookup<K, T>(this Dictionary<K, T> dictionary, K key) where K: notnull
|
||||||
=> dictionary.TryGetValue(key, out T? value) ? Option.Some(value) : Option.None;
|
=> dictionary.TryGetValue(key, out T? value) ? Optional.Some(value) : Optional.None;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,8 @@ namespace Sanchime.Functional.Extensions;
|
||||||
public static class EnumExtension
|
public static class EnumExtension
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 将字符串转换为相应的枚举值的<see cref="Option"/
|
/// 将字符串转换为相应的枚举值的<see cref="Optional"/
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static Option<T> Parse<T>(this string @this) where T : struct
|
public static Option<T> Parse<T>(this string @this) where T : struct
|
||||||
=> Enum.TryParse(@this, out T val) ? Option.Some(val) : Option.None;
|
=> Enum.TryParse(@this, out T val) ? Optional.Some(val) : Optional.None;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ public static class IEnumerableExtension
|
||||||
public static Func<T, IEnumerable<T>> Return<T>() => t => List(t);
|
public static Func<T, IEnumerable<T>> Return<T>() => t => List(t);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 将序列内第一条元素转换为<see cref="Option"/>
|
/// 将序列内第一条元素转换为<see cref="Optional"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="source"></param>
|
/// <param name="source"></param>
|
||||||
/// <typeparam name="T"></typeparam>
|
/// <typeparam name="T"></typeparam>
|
||||||
|
@ -20,14 +20,14 @@ public static class IEnumerableExtension
|
||||||
{
|
{
|
||||||
if (source is null)
|
if (source is null)
|
||||||
{
|
{
|
||||||
return Option.None;
|
return Optional.None;
|
||||||
}
|
}
|
||||||
var first = source.FirstOrDefault();
|
var first = source.FirstOrDefault();
|
||||||
return first is not null ? Option.Some(first) : Option.None;
|
return first is not null ? Optional.Some(first) : Optional.None;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 给定谓词,查询序列内第一条数据并将其转换为<see cref="Option"/>
|
/// 给定谓词,查询序列内第一条数据并将其转换为<see cref="Optional"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="source">数据源</param>
|
/// <param name="source">数据源</param>
|
||||||
/// <param name="predicate">谓词</param>
|
/// <param name="predicate">谓词</param>
|
||||||
|
@ -37,14 +37,14 @@ public static class IEnumerableExtension
|
||||||
{
|
{
|
||||||
if (source is null)
|
if (source is null)
|
||||||
{
|
{
|
||||||
return Option.None;
|
return Optional.None;
|
||||||
}
|
}
|
||||||
var first = source.Where(predicate).FirstOrDefault();
|
var first = source.Where(predicate).FirstOrDefault();
|
||||||
return first is not null ? Option.Some(first) : Option.None;
|
return first is not null ? Optional.Some(first) : Optional.None;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 将序列内最后一个元素转换为<see cref="Option"/>
|
/// 将序列内最后一个元素转换为<see cref="Optional"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="source"></param>
|
/// <param name="source"></param>
|
||||||
/// <typeparam name="T"></typeparam>
|
/// <typeparam name="T"></typeparam>
|
||||||
|
@ -53,14 +53,14 @@ public static class IEnumerableExtension
|
||||||
{
|
{
|
||||||
if (source is null)
|
if (source is null)
|
||||||
{
|
{
|
||||||
return Option.None;
|
return Optional.None;
|
||||||
}
|
}
|
||||||
var tail = source.LastOrDefault();
|
var tail = source.LastOrDefault();
|
||||||
return tail is not null ? Option.Some(tail) : Option.None;
|
return tail is not null ? Optional.Some(tail) : Optional.None;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 给定谓词,查询序列内最后一条数据并将其转换为<see cref="Option"/>
|
/// 给定谓词,查询序列内最后一条数据并将其转换为<see cref="Optional"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="source">数据源</param>
|
/// <param name="source">数据源</param>
|
||||||
/// <param name="predicate">谓词</param>
|
/// <param name="predicate">谓词</param>
|
||||||
|
@ -70,10 +70,10 @@ public static class IEnumerableExtension
|
||||||
{
|
{
|
||||||
if (source is null)
|
if (source is null)
|
||||||
{
|
{
|
||||||
return Option.None;
|
return Optional.None;
|
||||||
}
|
}
|
||||||
var last = source.Where(predicate).LastOrDefault();
|
var last = source.Where(predicate).LastOrDefault();
|
||||||
return last is not null ? Option.Some(last) : Option.None;
|
return last is not null ? Optional.Some(last) : Optional.None;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static R Match<T, R>(this IEnumerable<T> source, Func<R> Empty, Func<T, IEnumerable<T>, R> Otherwise)
|
public static R Match<T, R>(this IEnumerable<T> source, Func<R> Empty, Func<T, IEnumerable<T>, R> Otherwise)
|
||||||
|
|
|
@ -3,8 +3,8 @@ namespace Sanchime.Functional.Extensions;
|
||||||
public static class NullableExtension
|
public static class NullableExtension
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 将<see cref="Nullable"/>值转换为<see cref="Option"/>
|
/// 将<see cref="Nullable"/>值转换为<see cref="Optional"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static Option<T> ToOption<T>(this Nullable<T> @this) where T : struct
|
public static Option<T> ToOption<T>(this Nullable<T> @this) where T : struct
|
||||||
=> @this.HasValue ? Option.Some(@this.Value) : Option.None;
|
=> @this.HasValue ? Optional.Some(@this.Value) : Optional.None;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,7 @@ namespace Sanchime.Functional.Extensions;
|
||||||
|
|
||||||
public static class OptionExtension
|
public static class OptionExtension
|
||||||
{
|
{
|
||||||
public static Unit Match<T>(this Option<T> option, Action None, Action<T> Some)
|
|
||||||
=> option.Match(None.ToFunc(), Some.ToFunc());
|
|
||||||
|
|
||||||
#region 函子: 同一范畴内不同对象之间的态射
|
#region 函子: 同一范畴内不同对象之间的态射
|
||||||
|
|
||||||
|
@ -13,27 +12,18 @@ public static class OptionExtension
|
||||||
// public static Option<R> Map<T, R>(this Some<T> some, Func<T, R> mapping)
|
// public static Option<R> Map<T, R>(this Some<T> some, Func<T, R> mapping)
|
||||||
// => Option.Some(mapping(some.Value));
|
// => Option.Some(mapping(some.Value));
|
||||||
|
|
||||||
public static Option<R> Map<T, R>(this Option<T> option, Func<T, R> mapping)
|
// public static Option<R> Map<T, R>(this Option<T> option, Func<T, R> mapping)
|
||||||
=> option.Match(() => Option.None, (val) => Option.Some(mapping(val)));
|
// => option.Match(() => Option.None, (val) => Option.Some(mapping(val)));
|
||||||
|
|
||||||
// public static Option<Func<T2, R>> Map<T1, T2, R>(this Option<T1> option, Func<T1, T2, R> mapping)
|
// public static IOption Map<T1, T2, R>(this Option<T1> option, Func<T1, T2, R> mapping)
|
||||||
// => option.Map(mapping.Curry());
|
// => option.Map(mapping.Curry());
|
||||||
|
|
||||||
// public static Option<Func<T2, T3, R>> Map<T1, T2, T3, R>(this Option<T1> option, Func<T1, T2, T3, R> mapping)
|
// public static IOption Map<T1, T2, T3, R>(this Option<T1> option, Func<T1, T2, T3, R> mapping)
|
||||||
// => option.Map(mapping.CurryFirst());
|
// => option.Map(mapping.CurryFirst());
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region 单子: 自函子范畴上的幺半群
|
#region 单子: 自函子范畴上的幺半群
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Return自然变换: 将上下文无关的值导入至上下文有关的世界
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value"></param>
|
|
||||||
/// <typeparam name="T"></typeparam>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static Option<T> Return<T>(T value)
|
|
||||||
=> value is null ? Option.None : Option.Some(value);
|
|
||||||
|
|
||||||
|
|
||||||
public static Option<R> Bind<T, R>(this Option<T> option, Func<T, Option<R>> binding)
|
public static Option<R> Bind<T, R>(this Option<T> option, Func<T, Option<R>> binding)
|
||||||
=> option.Match(() => new Option<R>(), binding);
|
=> option.Match(() => new Option<R>(), binding);
|
||||||
|
@ -46,12 +36,12 @@ public static class OptionExtension
|
||||||
|
|
||||||
// #region 应用函子
|
// #region 应用函子
|
||||||
|
|
||||||
// public static Option<R> Apply<T, R>(this Option<Func<T, R>> option, Option<T> value)
|
public static Option<R> Apply<T, R>(this Option<Func<T, R>> option, Option<T> value)
|
||||||
// => option.Match(
|
=> option.Match(
|
||||||
// None: () => Option.None,
|
None: () => Optional.None,
|
||||||
// Some: (apply) => value.Match(
|
Some: (apply) => value.Match(
|
||||||
// None: () => Option.None,
|
None: () => Optional.None,
|
||||||
// Some: (val) => Option.Some(apply(val))));
|
Some: (val) => Optional.Some(apply(val))));
|
||||||
|
|
||||||
// public static Option<Func<T2, R>> Apply<T1, T2, R>(this Option<Func<T1, T2, R>> option, Option<T1> value)
|
// public static Option<Func<T2, R>> Apply<T1, T2, R>(this Option<Func<T1, T2, R>> option, Option<T1> value)
|
||||||
// => option.Map(CurryingExtension.Curry).Apply(value);
|
// => option.Map(CurryingExtension.Curry).Apply(value);
|
||||||
|
@ -95,7 +85,7 @@ public static class OptionExtension
|
||||||
=> left.Match(() => right(), (_) => left);
|
=> left.Match(() => right(), (_) => left);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 将<see cref="Option"转为<see cref="Either"/>
|
/// 将<see cref="Optional"转为<see cref="Either"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="option"></param>
|
/// <param name="option"></param>
|
||||||
/// <param name="error"></param>
|
/// <param name="error"></param>
|
||||||
|
@ -111,18 +101,18 @@ public static class OptionExtension
|
||||||
|
|
||||||
#region Linq式
|
#region Linq式
|
||||||
|
|
||||||
// public static Option<R> Select<T, R>(this Option<T> source, Func<T, R> mapping)
|
public static IOption Select<T, R>(this Option<T> source, Func<T, R> mapping)
|
||||||
// => source.Map(mapping);
|
=> source.Map(mapping);
|
||||||
|
|
||||||
public static Option<T> Where<T, R>(this Option<T> source, Func<T, bool> predicate)
|
public static Option<T> Where<T, R>(this Option<T> source, Func<T, bool> predicate)
|
||||||
=> source.Match(() => Option.None, (val) => predicate(val) ? source : Option.None);
|
=> source.Match(() => Optional.None, (val) => predicate(val) ? source : Optional.None);
|
||||||
|
|
||||||
public static Option<RR> SelectMany<T, R, RR>(this Option<T> source, Func<T, Option<R>> binding, Func<T, R, RR> project)
|
public static Option<RR> SelectMany<T, R, RR>(this Option<T> source, Func<T, Option<R>> binding, Func<T, R, RR> project)
|
||||||
=> source.Match(
|
=> source.Match(
|
||||||
None: () => Option.None,
|
None: () => Optional.None,
|
||||||
Some: (val) => binding(val).Match(
|
Some: (val) => binding(val).Match(
|
||||||
None: () => Option.None,
|
None: () => Optional.None,
|
||||||
Some: (res) => Option.Some(project(val, res))));
|
Some: (res) => Optional.Some(project(val, res))));
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ public interface IEither<TLeft, TRight> : IEither
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IEither : IFunctor
|
public interface IEither
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,16 +0,0 @@
|
||||||
namespace Sanchime.Functional.Products;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 应用函子
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TCategory"></typeparam>
|
|
||||||
public interface IApplicative<TCategory> : IApplicative, IFunctor<TCategory>
|
|
||||||
where TCategory : ICategory
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public interface IApplicative : IFunctor
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
namespace Sanchime.Functional.Products;
|
|
||||||
|
|
||||||
public interface ICategory
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
namespace Sanchime.Functional.Products;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 函子
|
|
||||||
/// 同一范畴内不同对象之间的映射
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TCategory"></typeparam>
|
|
||||||
public interface IFunctor<TCategory, TValue> : IFunctor
|
|
||||||
where TCategory : ICategory
|
|
||||||
{
|
|
||||||
TCategory Map<TResult>(Func<TValue, TResult> mapping);
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface IFunctor<TCategory> : IFunctor
|
|
||||||
where TCategory : ICategory
|
|
||||||
{
|
|
||||||
TCategory Map<TValue, TResult>(Func<TValue, TResult> mapping);
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface IFunctor : ICategory
|
|
||||||
{
|
|
||||||
public TResult Map<TResult>(Func<ICategory, TResult> mapping)
|
|
||||||
=> mapping(this);
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
namespace Sanchime.Functional.Products;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 单子
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TCategory"></typeparam>
|
|
||||||
public interface IMonad<TCategory> : IApplicative<TCategory>
|
|
||||||
where TCategory : ICategory
|
|
||||||
{
|
|
||||||
}
|
|
|
@ -5,12 +5,16 @@ using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Sanchime.Functional.Products;
|
namespace Sanchime.Functional.Products;
|
||||||
|
|
||||||
public interface IOption : IFunctor
|
public interface IOption
|
||||||
{
|
{
|
||||||
bool IsSome { get; }
|
bool IsSome { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IOption<TValue> : IOption, IFunctor<IOption, TValue>
|
/// <summary>
|
||||||
|
/// 选项
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TValue">选项内部维护的值</typeparam>
|
||||||
|
public interface IOption<out TValue> : IOption
|
||||||
{
|
{
|
||||||
TValue Value { get; }
|
TValue Value { get; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
namespace Sanchime.Functional.Products;
|
namespace Sanchime.Functional.Products;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <see cref="Option"/>的<see cref="None"/>状态
|
/// <see cref="Optional"/>的<see cref="None"/>状态
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly partial struct None : IOption
|
public readonly partial struct None : IOption
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 静态构造形成单例
|
||||||
|
/// </summary>
|
||||||
|
static None() { }
|
||||||
public bool IsSome => false;
|
public bool IsSome => false;
|
||||||
internal static readonly None Default = new();
|
internal static readonly None Default = new();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Sanchime.Functional.Products;
|
|
||||||
|
|
||||||
public readonly partial struct None : IFunctor<None>
|
|
||||||
{
|
|
||||||
public None Map<TValue, TResult>(Func<TValue, TResult> mapping)
|
|
||||||
=> Option.None;
|
|
||||||
}
|
|
|
@ -1,6 +1,8 @@
|
||||||
|
using Sanchime.Functional.Extensions;
|
||||||
|
|
||||||
namespace Sanchime.Functional.Products;
|
namespace Sanchime.Functional.Products;
|
||||||
|
|
||||||
public static class Option
|
public static class Optional
|
||||||
{
|
{
|
||||||
public static None None => None.Default;
|
public static None None => None.Default;
|
||||||
public static Option<TValue> Some<TValue>(TValue value) => new Some<TValue>(value);
|
public static Option<TValue> Some<TValue>(TValue value) => new Some<TValue>(value);
|
||||||
|
@ -18,39 +20,39 @@ public readonly partial struct Option<TValue> : IOption<TValue>, IEquatable<None
|
||||||
=> (_isSome, _value) = (true, value ?? throw new ArgumentNullException(nameof(value)));
|
=> (_isSome, _value) = (true, value ?? throw new ArgumentNullException(nameof(value)));
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 将<see cref="None"/>转换为<see cref="Option"/>
|
/// 将<see cref="None"/>转换为<see cref="Optional"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="_"></param>
|
/// <param name="_"></param>
|
||||||
public static implicit operator Option<TValue>(None _)
|
public static implicit operator Option<TValue>(None _)
|
||||||
=> new();
|
=> new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 将<see cref="Some"/>转换为<see cref="Option"/>
|
/// 将<see cref="Some"/>转换为<see cref="Optional"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="some"></param>
|
/// <param name="some"></param>
|
||||||
public static implicit operator Option<TValue>(Some<TValue> some)
|
public static implicit operator Option<TValue>(Some<TValue> some)
|
||||||
=> new(some.Value);
|
=> new(some.Value);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 将常规值提升至<see cref="Option"/>
|
/// 将常规值提升至<see cref="Optional"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="value"></param>
|
/// <param name="value"></param>
|
||||||
public static implicit operator Option<TValue>(TValue value)
|
public static implicit operator Option<TValue>(TValue value)
|
||||||
=> value is null ? Option.None : Option.Some(value);
|
=> value is null ? Optional.None : Optional.Some(value);
|
||||||
|
|
||||||
public bool IsSome => this.Match(() => false, (_) => true);
|
public bool IsSome => _isSome;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取<see cref="Option"/>内部的值,如果为<see cref="Option.None"/>则抛出异常
|
/// 获取<see cref="Optional"/>内部的值,如果为<see cref="Optional.None"/>则抛出异常
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public TValue ValueUnsafe => this.Match(() => throw new InvalidOperationException(), val => val);
|
public TValue ValueUnsafe => this.Match(() => throw new InvalidOperationException(), val => val);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取<see cref="Option"/>内部的值,如果为<see cref="Option.None"/>则返回默认值
|
/// 获取<see cref="Optional"/>内部的值,如果为<see cref="Optional.None"/>则返回默认值
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public TValue Value => this.Match(() => default!, val => val);
|
public TValue Value => _isNone ? default! : _value;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 转换为序列
|
/// 转换为序列
|
||||||
|
@ -60,15 +62,7 @@ public readonly partial struct Option<TValue> : IOption<TValue>, IEquatable<None
|
||||||
{
|
{
|
||||||
if (_isSome) yield return _value;
|
if (_isSome) yield return _value;
|
||||||
}
|
}
|
||||||
/// <summary>
|
|
||||||
/// 接收两个函数,根据<see cref="Option"/>的状态进行求值
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TResult"></typeparam>
|
|
||||||
/// <param name="None">None状态</param>
|
|
||||||
/// <param name="Some">Some状态</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public TResult Match<TResult>(Func<TResult> None, Func<TValue, TResult> Some)
|
|
||||||
=> _isSome ? Some(_value) : None();
|
|
||||||
|
|
||||||
public bool Equals(Option<TValue> other)
|
public bool Equals(Option<TValue> other)
|
||||||
=> this._isSome == other._isSome
|
=> this._isSome == other._isSome
|
||||||
|
|
|
@ -2,18 +2,39 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Sanchime.Functional.Extensions;
|
||||||
|
|
||||||
namespace Sanchime.Functional.Products;
|
namespace Sanchime.Functional.Products;
|
||||||
|
|
||||||
public readonly partial struct Option<TValue>
|
public static class OptionFunctor
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 接收两个函数,根据<see cref="Optional"/>的状态进行求值
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TResult"></typeparam>
|
||||||
|
/// <param name="None">None状态</param>
|
||||||
|
/// <param name="Some">Some状态</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static TResult Match<TValue, TResult>(this IOption<TValue> option, Func<TResult> None, Func<TValue, TResult> Some)
|
||||||
|
=> option.IsSome ? Some(option.Value) : None();
|
||||||
|
|
||||||
|
public static Unit Match<TValue>(this IOption<TValue> option, Action None, Action<TValue> Some)
|
||||||
|
=> option.Match(None.ToFunc(), Some.ToFunc());
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 映射
|
/// 映射
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="option"></param>
|
||||||
/// <param name="mapping"></param>
|
/// <param name="mapping"></param>
|
||||||
|
/// <typeparam name="TValue"></typeparam>
|
||||||
/// <typeparam name="TResult"></typeparam>
|
/// <typeparam name="TResult"></typeparam>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public IOption Map<TResult>(Func<TValue, TResult> mapping)
|
public static IOption<TResult> Map<TValue, TResult>(this IOption<TValue> option, Func<TValue, TResult> mapping)
|
||||||
=> this.Match(() => Option.None, value => Option.Some(mapping(value)));
|
=> option.Match(() => Optional.None, value => Optional.Some(mapping(value)));
|
||||||
|
|
||||||
|
public static IOption<Func<TValue1, TResult>> Map<TValue, TValue1, TResult>(this IOption<TValue> option,Func<TValue, TValue1, TResult> mapping)
|
||||||
|
=> option.Map(mapping.Curry());
|
||||||
|
|
||||||
|
public static IOption<Func<TValue1, TValue2, TResult>> Map<TValue, TValue1, TValue2, TResult>(this IOption<TValue> option, Func<TValue, TValue1, TValue2, TResult> mapping)
|
||||||
|
=> option.Map(mapping.CurryFirst());
|
||||||
}
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
namespace Sanchime.Functional.Products;
|
||||||
|
|
||||||
|
public readonly partial struct Option<TValue>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Return自然变换: 将上下文无关的值导入至上下文有关的世界
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value"></param>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static IOption Return<T>(T value)
|
||||||
|
=> value is null ? Optional.None : Optional.Some(value);
|
||||||
|
|
||||||
|
public static IOption Return(TValue value)
|
||||||
|
=> Return<TValue>(value);
|
||||||
|
}
|
|
@ -1,16 +1,15 @@
|
||||||
namespace Sanchime.Functional.Products;
|
namespace Sanchime.Functional.Products;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <see cref="Option"/>的<see cref="Some"/>状态
|
/// <see cref="Optional"/>的<see cref="Some"/>状态
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="TValue"></typeparam>
|
/// <typeparam name="TValue"></typeparam>
|
||||||
public readonly struct Some<TValue> : IOption<TValue>
|
public readonly struct Some<TValue> : IOption
|
||||||
{
|
{
|
||||||
public bool IsSome => Value is not null;
|
public bool IsSome => Value is not null;
|
||||||
public TValue Value { get; }
|
public TValue Value { get; }
|
||||||
internal Some(TValue value) => Value = value ?? throw new ArgumentNullException(nameof(value), "不能在Some状态中包装null值, 应该使用None");
|
internal Some(TValue value) => Value = value ?? throw new ArgumentNullException(nameof(value), "不能在Some状态中包装null值, 应该使用None");
|
||||||
|
|
||||||
|
|
||||||
public IOption Map<TResult>(Func<TValue, TResult> mapping)
|
public IOption Map<TResult>(Func<TValue, TResult> mapping)
|
||||||
=> Option.Some(mapping(this.Value));
|
=> Optional.Some(mapping(this.Value));
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,38 +3,51 @@ using Sanchime.Functional.Extensions;
|
||||||
using Sanchime.Toolkits;
|
using Sanchime.Toolkits;
|
||||||
|
|
||||||
|
|
||||||
void foo(Option<int> option)
|
try
|
||||||
{
|
{
|
||||||
|
void foo(Option<int> option)
|
||||||
|
{
|
||||||
var res = option.Map(x => x + 2);
|
var res = option.Map(x => x + 2);
|
||||||
res.WriteLine();
|
res.WriteLine();
|
||||||
}
|
}
|
||||||
"预计打印Some(12)".WriteLine();
|
|
||||||
foo(10);
|
|
||||||
"预计打印None".WriteLine();
|
|
||||||
foo(Option.None);
|
|
||||||
|
|
||||||
"预计打印Char".WriteLine();
|
"预计打印Some(12)".WriteLine();
|
||||||
Option.Some(1)
|
foo(10);
|
||||||
.Map(x => (float)x + 1.2)
|
"预计打印None".WriteLine();
|
||||||
|
foo(Optional.None);
|
||||||
|
|
||||||
|
"预计打印Some(String)".WriteLine();
|
||||||
|
Optional.Some(1)
|
||||||
|
.Map(x => x + 1.2)
|
||||||
.Map(x => x.ToString())
|
.Map(x => x.ToString())
|
||||||
.Map(x => x.GetType().Name)
|
.Map(x => x.GetType().Name)
|
||||||
.ForEach(x => x.WriteLine());
|
.WriteLine();
|
||||||
|
|
||||||
// 测试Option的Bind
|
// 测试Option的Bind
|
||||||
var parse = (string s) => Int32.TryParse(s, out int i) ? Option.Some(i) : Option.None;
|
var parse = (string s) => Int32.TryParse(s, out int i) ? Optional.Some(i) : Optional.None;
|
||||||
var foo1 = (string s) => s.Pipe(parse).Bind(Age.Of);
|
var foo1 = (string s) => s.Pipe(parse).Bind(Age.Of);
|
||||||
|
"预计打印Some(111)".WriteLine();
|
||||||
foo1("111").WriteLine();
|
foo1("111").WriteLine();
|
||||||
foo1("aaa").WriteLine();
|
"预计打印None".WriteLine();
|
||||||
foo1("123").WriteLine();
|
foo1("aaa").WriteLine();
|
||||||
|
"预计打印Some(123)".WriteLine();
|
||||||
|
foo1("123").WriteLine();
|
||||||
// 管道
|
// 管道
|
||||||
foo1("1ab").Pipe(x => Console.WriteLine(x));
|
"预计打印None".WriteLine();
|
||||||
|
foo1("1ab").Pipe(x => x.WriteLine());
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
ex.Message.WriteLine();
|
||||||
|
ex.StackTrace.WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
public struct Age
|
public struct Age
|
||||||
{
|
{
|
||||||
private int _value;
|
private int _value;
|
||||||
|
|
||||||
public static Option<Age> Of(int age)
|
public static Option<Age> Of(int age)
|
||||||
=> IsValid(age) ? Option.Some(new Age(age)) : Option.None;
|
=> IsValid(age) ? Optional.Some(new Age(age)) : Optional.None;
|
||||||
|
|
||||||
private Age(int age)
|
private Age(int age)
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,7 +5,7 @@ public static class Basic
|
||||||
{
|
{
|
||||||
public static void WriteLine<T>(this T @this)
|
public static void WriteLine<T>(this T @this)
|
||||||
{
|
{
|
||||||
Debug.WriteLine(@this);
|
Console.WriteLine(@this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void WriteLine<T>(this T @this, Func<T, T> func)
|
public static void WriteLine<T>(this T @this, Func<T, T> func)
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Sanchime/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
Loading…
Reference in New Issue