重新调整Option
This commit is contained in:
parent
627f2e83a1
commit
59f4e8c110
|
@ -16,11 +16,11 @@ public static class OptionExtension
|
|||
public static Option<R> Map<T, R>(this Option<T> option, Func<T, R> mapping)
|
||||
=> 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)
|
||||
=> option.Map(mapping.Curry());
|
||||
// public static Option<Func<T2, R>> Map<T1, T2, R>(this Option<T1> option, Func<T1, T2, R> mapping)
|
||||
// => 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)
|
||||
=> option.Map(mapping.CurryFirst());
|
||||
// public static Option<Func<T2, T3, R>> Map<T1, T2, T3, R>(this Option<T1> option, Func<T1, T2, T3, R> mapping)
|
||||
// => option.Map(mapping.CurryFirst());
|
||||
#endregion
|
||||
|
||||
#region 单子: 自函子范畴上的幺半群
|
||||
|
@ -44,40 +44,40 @@ public static class OptionExtension
|
|||
|
||||
#endregion
|
||||
|
||||
#region 应用函子
|
||||
// #region 应用函子
|
||||
|
||||
public static Option<R> Apply<T, R>(this Option<Func<T, R>> option, Option<T> value)
|
||||
=> option.Match(
|
||||
None: () => Option.None,
|
||||
Some: (apply) => value.Match(
|
||||
None: () => Option.None,
|
||||
Some: (val) => Option.Some(apply(val))));
|
||||
// public static Option<R> Apply<T, R>(this Option<Func<T, R>> option, Option<T> value)
|
||||
// => option.Match(
|
||||
// None: () => Option.None,
|
||||
// Some: (apply) => value.Match(
|
||||
// None: () => Option.None,
|
||||
// Some: (val) => Option.Some(apply(val))));
|
||||
|
||||
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);
|
||||
// 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);
|
||||
|
||||
public static Option<Func<T2, T3, R>> Apply<T1, T2, T3, R>(this Option<Func<T1, T2, T3, R>> option, Option<T1> value)
|
||||
=> option.Map(CurryingExtension.CurryFirst).Apply(value);
|
||||
// public static Option<Func<T2, T3, R>> Apply<T1, T2, T3, R>(this Option<Func<T1, T2, T3, R>> option, Option<T1> value)
|
||||
// => option.Map(CurryingExtension.CurryFirst).Apply(value);
|
||||
|
||||
public static Option<Func<T2, T3, T4, R>> Apply<T1, T2, T3, T4, R>(this Option<Func<T1, T2, T3, T4, R>> option, Option<T1> value)
|
||||
=> option.Map(CurryingExtension.CurryFirst).Apply(value);
|
||||
// public static Option<Func<T2, T3, T4, R>> Apply<T1, T2, T3, T4, R>(this Option<Func<T1, T2, T3, T4, R>> option, Option<T1> value)
|
||||
// => option.Map(CurryingExtension.CurryFirst).Apply(value);
|
||||
|
||||
public static Option<Func<T2, T3, T4, T5, R>> Apply<T1, T2, T3, T4, T5, R>(this Option<Func<T1, T2, T3, T4, T5, R>> option, Option<T1> value)
|
||||
=> option.Map(CurryingExtension.CurryFirst).Apply(value);
|
||||
// public static Option<Func<T2, T3, T4, T5, R>> Apply<T1, T2, T3, T4, T5, R>(this Option<Func<T1, T2, T3, T4, T5, R>> option, Option<T1> value)
|
||||
// => option.Map(CurryingExtension.CurryFirst).Apply(value);
|
||||
|
||||
public static Option<Func<T2, T3, T4, T5, T6, R>> Apply<T1, T2, T3, T4, T5, T6, R>(this Option<Func<T1, T2, T3, T4, T5, T6, R>> option, Option<T1> value)
|
||||
=> option.Map(CurryingExtension.CurryFirst).Apply(value);
|
||||
// public static Option<Func<T2, T3, T4, T5, T6, R>> Apply<T1, T2, T3, T4, T5, T6, R>(this Option<Func<T1, T2, T3, T4, T5, T6, R>> option, Option<T1> value)
|
||||
// => option.Map(CurryingExtension.CurryFirst).Apply(value);
|
||||
|
||||
public static Option<Func<T2, T3, T4, T5, T6, T7, R>> Apply<T1, T2, T3, T4, T5, T6, T7, R>(this Option<Func<T1, T2, T3, T4, T5, T6, T7, R>> option, Option<T1> value)
|
||||
=> option.Map(CurryingExtension.CurryFirst).Apply(value);
|
||||
// public static Option<Func<T2, T3, T4, T5, T6, T7, R>> Apply<T1, T2, T3, T4, T5, T6, T7, R>(this Option<Func<T1, T2, T3, T4, T5, T6, T7, R>> option, Option<T1> value)
|
||||
// => option.Map(CurryingExtension.CurryFirst).Apply(value);
|
||||
|
||||
public static Option<Func<T2, T3, T4, T5, T6, T7, T8, R>> Apply<T1, T2, T3, T4, T5, T6, T7, T8, R>(this Option<Func<T1, T2, T3, T4, T5, T6, T7, T8, R>> option, Option<T1> value)
|
||||
=> option.Map(CurryingExtension.CurryFirst).Apply(value);
|
||||
// public static Option<Func<T2, T3, T4, T5, T6, T7, T8, R>> Apply<T1, T2, T3, T4, T5, T6, T7, T8, R>(this Option<Func<T1, T2, T3, T4, T5, T6, T7, T8, R>> option, Option<T1> value)
|
||||
// => option.Map(CurryingExtension.CurryFirst).Apply(value);
|
||||
|
||||
public static Option<Func<T2, T3, T4, T5, T6, T7, T8, T9, R>> Apply<T1, T2, T3, T4, T5, T6, T7, T8, T9, R>(this Option<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, R>> option, Option<T1> value)
|
||||
=> option.Map(CurryingExtension.CurryFirst).Apply(value);
|
||||
// public static Option<Func<T2, T3, T4, T5, T6, T7, T8, T9, R>> Apply<T1, T2, T3, T4, T5, T6, T7, T8, T9, R>(this Option<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, R>> option, Option<T1> value)
|
||||
// => option.Map(CurryingExtension.CurryFirst).Apply(value);
|
||||
|
||||
#endregion
|
||||
// #endregion
|
||||
|
||||
public static T GetOrElse<T>(this Option<T> option, T @default)
|
||||
=> option.Match(() => @default, (val) => val);
|
||||
|
@ -103,16 +103,16 @@ public static class OptionExtension
|
|||
/// <typeparam name="R"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static Either<L, R> ToEither<L, R>(this Option<L> option, R error)
|
||||
=> option.IsSome() ? Either.Right(error) : Either.Left(option.Value);
|
||||
=> option.IsSome ? Either.Right(error) : Either.Left(option.Value);
|
||||
|
||||
public static Either<L, string> ToEither<L, R>(this Option<L> option, string error)
|
||||
=> option.IsSome() ? Either.Right(error) : Either.Left(option.Value);
|
||||
=> option.IsSome ? Either.Right(error) : Either.Left(option.Value);
|
||||
|
||||
|
||||
#region Linq式
|
||||
|
||||
public static Option<R> Select<T, R>(this Option<T> source, Func<T, R> mapping)
|
||||
=> source.Map(mapping);
|
||||
// public static Option<R> Select<T, R>(this Option<T> source, Func<T, R> mapping)
|
||||
// => source.Map(mapping);
|
||||
|
||||
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);
|
||||
|
|
|
@ -5,12 +5,12 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace Sanchime.Functional.Products;
|
||||
|
||||
public interface IEither<TLeft, TRight> : IEither, IFunctor
|
||||
public interface IEither<TLeft, TRight> : IEither
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public interface IEither
|
||||
public interface IEither : IFunctor
|
||||
{
|
||||
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
namespace Sanchime.Functional.Products;
|
||||
|
||||
public readonly struct Left<TLeft> : IEither
|
||||
public readonly partial struct Left<TLeft> : IEither
|
||||
{
|
||||
internal TLeft Value { get; }
|
||||
internal Left(TLeft value)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
namespace Sanchime.Functional.Products;
|
||||
|
||||
public readonly struct Right<TRight> : IEither
|
||||
public readonly partial struct Right<TRight> : IEither
|
||||
{
|
||||
internal TRight Value { get; }
|
||||
internal Right(TRight value)
|
||||
|
|
|
@ -5,14 +5,20 @@ namespace Sanchime.Functional.Products;
|
|||
/// 同一范畴内不同对象之间的映射
|
||||
/// </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<T>(Func<T, TCategory> mapping);
|
||||
TCategory Map<TValue, TResult>(Func<TValue, TResult> mapping);
|
||||
}
|
||||
|
||||
|
||||
public interface IFunctor : ICategory
|
||||
{
|
||||
|
||||
public TResult Map<TResult>(Func<ICategory, TResult> mapping)
|
||||
=> mapping(this);
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Sanchime.Functional.Products;
|
||||
|
||||
|
||||
public interface IMatchable<TValue>
|
||||
{
|
||||
TResult Match<TResult>(Func<TResult> left, Func<TValue, TResult> right);
|
||||
|
||||
Unit Match(Action left, Action<TValue> right);
|
||||
}
|
||||
|
||||
public interface IMatchable
|
||||
{
|
||||
TResult Match<TValue, TResult>(Func<TResult> left, Func<TValue, TResult> right);
|
||||
|
||||
Unit Match<TValue>(Action left, Action<TValue> right);
|
||||
}
|
|
@ -5,12 +5,12 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace Sanchime.Functional.Products;
|
||||
|
||||
public interface IOption : ICategory
|
||||
public interface IOption : IFunctor
|
||||
{
|
||||
|
||||
bool IsSome { get; }
|
||||
}
|
||||
|
||||
public interface IOption<TValue> : IOption
|
||||
public interface IOption<TValue> : IOption, IFunctor<IOption, TValue>
|
||||
{
|
||||
TValue Value { get; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,5 +5,6 @@ namespace Sanchime.Functional.Products;
|
|||
/// </summary>
|
||||
public readonly partial struct None : IOption
|
||||
{
|
||||
public bool IsSome => false;
|
||||
internal static readonly None Default = new();
|
||||
}
|
||||
|
|
|
@ -7,6 +7,6 @@ namespace Sanchime.Functional.Products;
|
|||
|
||||
public readonly partial struct None : IFunctor<None>
|
||||
{
|
||||
public None Map<T>(Func<T, None> mapping)
|
||||
public None Map<TValue, TResult>(Func<TValue, TResult> mapping)
|
||||
=> Option.None;
|
||||
}
|
|
@ -38,7 +38,7 @@ public readonly partial struct Option<TValue> : IOption<TValue>, IEquatable<None
|
|||
public static implicit operator Option<TValue>(TValue value)
|
||||
=> value is null ? Option.None : Option.Some(value);
|
||||
|
||||
public bool IsSome() => this.Match(() => false, (_) => true);
|
||||
public bool IsSome => this.Match(() => false, (_) => true);
|
||||
|
||||
/// <summary>
|
||||
/// 获取<see cref="Option"/>内部的值,如果为<see cref="Option.None"/>则抛出异常
|
||||
|
|
|
@ -3,9 +3,17 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Sanchime.Functional.Products.Options;
|
||||
namespace Sanchime.Functional.Products;
|
||||
|
||||
public readonly partial struct Option<TValue> //: IFunctor<IOption>
|
||||
public readonly partial struct Option<TValue>
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 映射
|
||||
/// </summary>
|
||||
/// <param name="mapping"></param>
|
||||
/// <typeparam name="TResult"></typeparam>
|
||||
/// <returns></returns>
|
||||
public IOption Map<TResult>(Func<TValue, TResult> mapping)
|
||||
=> this.Match(() => Option.None, value => Option.Some(mapping(value)));
|
||||
|
||||
}
|
|
@ -4,11 +4,13 @@ namespace Sanchime.Functional.Products;
|
|||
/// <see cref="Option"/>的<see cref="Some"/>状态
|
||||
/// </summary>
|
||||
/// <typeparam name="TValue"></typeparam>
|
||||
public readonly struct Some<TValue> : IOption, IFunctor
|
||||
public readonly struct Some<TValue> : IOption<TValue>
|
||||
{
|
||||
internal TValue Value { get; }
|
||||
public bool IsSome => Value is not null;
|
||||
public TValue Value { get; }
|
||||
internal Some(TValue value) => Value = value ?? throw new ArgumentNullException(nameof(value), "不能在Some状态中包装null值, 应该使用None");
|
||||
|
||||
public Option<Some<TValue>> Map(Func<TValue, Some<TValue>> mapping)
|
||||
|
||||
public IOption Map<TResult>(Func<TValue, TResult> mapping)
|
||||
=> Option.Some(mapping(this.Value));
|
||||
}
|
||||
|
|
|
@ -2,32 +2,33 @@
|
|||
using Sanchime.Functional.Extensions;
|
||||
using Sanchime.Toolkits;
|
||||
|
||||
// Test<int> test = new Test<int>();
|
||||
|
||||
// Console.WriteLine(test.Map((Test<int> x) => {x.Value = 2; return x;}).Value);
|
||||
void foo(Option<int> option)
|
||||
{
|
||||
var res = option.Map(x => x + 2);
|
||||
res.WriteLine();
|
||||
}
|
||||
"预计打印Some(12)".WriteLine();
|
||||
foo(10);
|
||||
"预计打印None".WriteLine();
|
||||
foo(Option.None);
|
||||
|
||||
// Console.WriteLine(test.Value);
|
||||
|
||||
// foo(10);
|
||||
// foo(Option.None);
|
||||
|
||||
// void foo(Option<int> option)
|
||||
// {
|
||||
// var res = option.Map(x => x + 2);
|
||||
// res.WriteLine();
|
||||
// }
|
||||
|
||||
// Option.Some(1).Map(x => (float)x + 1.2).Map(x => x.ToString()).Map(x => x.GetType().Name).WriteLine();
|
||||
"预计打印Char".WriteLine();
|
||||
Option.Some(1)
|
||||
.Map(x => (float)x + 1.2)
|
||||
.Map(x => x.ToString())
|
||||
.Map(x => x.GetType().Name)
|
||||
.ForEach(x => x.WriteLine());
|
||||
|
||||
// 测试Option的Bind
|
||||
var parse = (string s) => Int32.TryParse(s, out int i) ? Option.Some(i) : Option.None;
|
||||
var foo = (string s) => s.Pipe(parse).Bind(Age.Of);
|
||||
var foo1 = (string s) => s.Pipe(parse).Bind(Age.Of);
|
||||
|
||||
foo("111").WriteLine();
|
||||
foo("aaa").WriteLine();
|
||||
foo("123").WriteLine();
|
||||
foo1("111").WriteLine();
|
||||
foo1("aaa").WriteLine();
|
||||
foo1("123").WriteLine();
|
||||
// 管道
|
||||
foo("1ab").Pipe(x => Console.WriteLine(x));
|
||||
foo1("1ab").Pipe(x => Console.WriteLine(x));
|
||||
public struct Age
|
||||
{
|
||||
private int _value;
|
||||
|
|
|
@ -3,7 +3,6 @@ namespace Sanchime.Toolkits;
|
|||
|
||||
public static class Basic
|
||||
{
|
||||
|
||||
public static void WriteLine<T>(this T @this)
|
||||
{
|
||||
Debug.WriteLine(@this);
|
||||
|
|
Loading…
Reference in New Issue