重新调整Option

This commit is contained in:
sanchime 2023-01-08 17:22:25 +08:00
parent 627f2e83a1
commit 59f4e8c110
14 changed files with 109 additions and 71 deletions

View File

@ -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);

View File

@ -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
{
}

View File

@ -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)

View File

@ -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)

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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; }
}
}

View File

@ -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();
}

View File

@ -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;
}

View File

@ -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"/>则抛出异常

View File

@ -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)));
}

View File

@ -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));
}

View File

@ -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;

View File

@ -3,7 +3,6 @@ namespace Sanchime.Toolkits;
public static class Basic
{
public static void WriteLine<T>(this T @this)
{
Debug.WriteLine(@this);