From 59f4e8c110ca2d0fb989f5439356a520d5deaa2a Mon Sep 17 00:00:00 2001 From: sanchime Date: Sun, 8 Jan 2023 17:22:25 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=96=B0=E8=B0=83=E6=95=B4Option?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Sanchime.Functional/Extensions/Option.cs | 64 +++++++++---------- .../Products/Eithers/IEither.cs | 4 +- Sanchime.Functional/Products/Eithers/Left.cs | 2 +- Sanchime.Functional/Products/Eithers/Right.cs | 2 +- Sanchime.Functional/Products/IFunctor.cs | 12 +++- Sanchime.Functional/Products/IMatchable.cs | 21 ++++++ .../Products/Options/IOption.cs | 8 +-- Sanchime.Functional/Products/Options/None.cs | 1 + .../Products/Options/NoneFunctor.cs | 2 +- .../Products/Options/Option.cs | 2 +- .../Products/Options/OptionFunctor.cs | 14 +++- Sanchime.Functional/Products/Options/Some.cs | 8 ++- Sanchime.Test/Program.cs | 39 +++++------ Sanchime.Toolkits/Basic.cs | 1 - 14 files changed, 109 insertions(+), 71 deletions(-) create mode 100644 Sanchime.Functional/Products/IMatchable.cs diff --git a/Sanchime.Functional/Extensions/Option.cs b/Sanchime.Functional/Extensions/Option.cs index 62ca2b6..d802293 100644 --- a/Sanchime.Functional/Extensions/Option.cs +++ b/Sanchime.Functional/Extensions/Option.cs @@ -16,11 +16,11 @@ public static class OptionExtension public static Option Map(this Option option, Func mapping) => option.Match(() => Option.None, (val) => Option.Some(mapping(val))); - public static Option> Map(this Option option, Func mapping) - => option.Map(mapping.Curry()); + // public static Option> Map(this Option option, Func mapping) + // => option.Map(mapping.Curry()); - public static Option> Map(this Option option, Func mapping) - => option.Map(mapping.CurryFirst()); + // public static Option> Map(this Option option, Func mapping) + // => option.Map(mapping.CurryFirst()); #endregion #region 单子: 自函子范畴上的幺半群 @@ -44,40 +44,40 @@ public static class OptionExtension #endregion - #region 应用函子 + // #region 应用函子 - public static Option Apply(this Option> option, Option value) - => option.Match( - None: () => Option.None, - Some: (apply) => value.Match( - None: () => Option.None, - Some: (val) => Option.Some(apply(val)))); + // public static Option Apply(this Option> option, Option value) + // => option.Match( + // None: () => Option.None, + // Some: (apply) => value.Match( + // None: () => Option.None, + // Some: (val) => Option.Some(apply(val)))); - public static Option> Apply(this Option> option, Option value) - => option.Map(CurryingExtension.Curry).Apply(value); + // public static Option> Apply(this Option> option, Option value) + // => option.Map(CurryingExtension.Curry).Apply(value); - public static Option> Apply(this Option> option, Option value) - => option.Map(CurryingExtension.CurryFirst).Apply(value); + // public static Option> Apply(this Option> option, Option value) + // => option.Map(CurryingExtension.CurryFirst).Apply(value); - public static Option> Apply(this Option> option, Option value) - => option.Map(CurryingExtension.CurryFirst).Apply(value); + // public static Option> Apply(this Option> option, Option value) + // => option.Map(CurryingExtension.CurryFirst).Apply(value); - public static Option> Apply(this Option> option, Option value) - => option.Map(CurryingExtension.CurryFirst).Apply(value); + // public static Option> Apply(this Option> option, Option value) + // => option.Map(CurryingExtension.CurryFirst).Apply(value); - public static Option> Apply(this Option> option, Option value) - => option.Map(CurryingExtension.CurryFirst).Apply(value); + // public static Option> Apply(this Option> option, Option value) + // => option.Map(CurryingExtension.CurryFirst).Apply(value); - public static Option> Apply(this Option> option, Option value) - => option.Map(CurryingExtension.CurryFirst).Apply(value); + // public static Option> Apply(this Option> option, Option value) + // => option.Map(CurryingExtension.CurryFirst).Apply(value); - public static Option> Apply(this Option> option, Option value) - => option.Map(CurryingExtension.CurryFirst).Apply(value); + // public static Option> Apply(this Option> option, Option value) + // => option.Map(CurryingExtension.CurryFirst).Apply(value); - public static Option> Apply(this Option> option, Option value) - => option.Map(CurryingExtension.CurryFirst).Apply(value); + // public static Option> Apply(this Option> option, Option value) + // => option.Map(CurryingExtension.CurryFirst).Apply(value); - #endregion + // #endregion public static T GetOrElse(this Option option, T @default) => option.Match(() => @default, (val) => val); @@ -103,16 +103,16 @@ public static class OptionExtension /// /// public static Either ToEither(this Option option, R error) - => option.IsSome() ? Either.Right(error) : Either.Left(option.Value); + => option.IsSome ? Either.Right(error) : Either.Left(option.Value); public static Either ToEither(this Option 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 Select(this Option source, Func mapping) - => source.Map(mapping); + // public static Option Select(this Option source, Func mapping) + // => source.Map(mapping); public static Option Where(this Option source, Func predicate) => source.Match(() => Option.None, (val) => predicate(val) ? source : Option.None); diff --git a/Sanchime.Functional/Products/Eithers/IEither.cs b/Sanchime.Functional/Products/Eithers/IEither.cs index 998c3f7..5d96db9 100644 --- a/Sanchime.Functional/Products/Eithers/IEither.cs +++ b/Sanchime.Functional/Products/Eithers/IEither.cs @@ -5,12 +5,12 @@ using System.Threading.Tasks; namespace Sanchime.Functional.Products; -public interface IEither : IEither, IFunctor +public interface IEither : IEither { } -public interface IEither +public interface IEither : IFunctor { } \ No newline at end of file diff --git a/Sanchime.Functional/Products/Eithers/Left.cs b/Sanchime.Functional/Products/Eithers/Left.cs index 7f6a9bf..9ee5f19 100644 --- a/Sanchime.Functional/Products/Eithers/Left.cs +++ b/Sanchime.Functional/Products/Eithers/Left.cs @@ -1,6 +1,6 @@ namespace Sanchime.Functional.Products; -public readonly struct Left : IEither +public readonly partial struct Left : IEither { internal TLeft Value { get; } internal Left(TLeft value) diff --git a/Sanchime.Functional/Products/Eithers/Right.cs b/Sanchime.Functional/Products/Eithers/Right.cs index e92ac8b..ac590f5 100644 --- a/Sanchime.Functional/Products/Eithers/Right.cs +++ b/Sanchime.Functional/Products/Eithers/Right.cs @@ -1,6 +1,6 @@ namespace Sanchime.Functional.Products; -public readonly struct Right : IEither +public readonly partial struct Right : IEither { internal TRight Value { get; } internal Right(TRight value) diff --git a/Sanchime.Functional/Products/IFunctor.cs b/Sanchime.Functional/Products/IFunctor.cs index e7a87be..c17ebf1 100644 --- a/Sanchime.Functional/Products/IFunctor.cs +++ b/Sanchime.Functional/Products/IFunctor.cs @@ -5,14 +5,20 @@ namespace Sanchime.Functional.Products; /// 同一范畴内不同对象之间的映射 /// /// +public interface IFunctor : IFunctor + where TCategory : ICategory +{ + TCategory Map(Func mapping); +} + public interface IFunctor : IFunctor where TCategory : ICategory { - TCategory Map(Func mapping); + TCategory Map(Func mapping); } - public interface IFunctor : ICategory { - + public TResult Map(Func mapping) + => mapping(this); } \ No newline at end of file diff --git a/Sanchime.Functional/Products/IMatchable.cs b/Sanchime.Functional/Products/IMatchable.cs new file mode 100644 index 0000000..1b430ba --- /dev/null +++ b/Sanchime.Functional/Products/IMatchable.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Sanchime.Functional.Products; + + +public interface IMatchable +{ + TResult Match(Func left, Func right); + + Unit Match(Action left, Action right); +} + +public interface IMatchable +{ + TResult Match(Func left, Func right); + + Unit Match(Action left, Action right); +} \ No newline at end of file diff --git a/Sanchime.Functional/Products/Options/IOption.cs b/Sanchime.Functional/Products/Options/IOption.cs index a1036ae..57e4fe1 100644 --- a/Sanchime.Functional/Products/Options/IOption.cs +++ b/Sanchime.Functional/Products/Options/IOption.cs @@ -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 : IOption +public interface IOption : IOption, IFunctor { TValue Value { get; } -} \ No newline at end of file +} diff --git a/Sanchime.Functional/Products/Options/None.cs b/Sanchime.Functional/Products/Options/None.cs index 296590c..5d9409f 100644 --- a/Sanchime.Functional/Products/Options/None.cs +++ b/Sanchime.Functional/Products/Options/None.cs @@ -5,5 +5,6 @@ namespace Sanchime.Functional.Products; /// public readonly partial struct None : IOption { + public bool IsSome => false; internal static readonly None Default = new(); } diff --git a/Sanchime.Functional/Products/Options/NoneFunctor.cs b/Sanchime.Functional/Products/Options/NoneFunctor.cs index 8ad6310..731498e 100644 --- a/Sanchime.Functional/Products/Options/NoneFunctor.cs +++ b/Sanchime.Functional/Products/Options/NoneFunctor.cs @@ -7,6 +7,6 @@ namespace Sanchime.Functional.Products; public readonly partial struct None : IFunctor { - public None Map(Func mapping) + public None Map(Func mapping) => Option.None; } \ No newline at end of file diff --git a/Sanchime.Functional/Products/Options/Option.cs b/Sanchime.Functional/Products/Options/Option.cs index f75ce5d..13b89ed 100644 --- a/Sanchime.Functional/Products/Options/Option.cs +++ b/Sanchime.Functional/Products/Options/Option.cs @@ -38,7 +38,7 @@ public readonly partial struct Option : IOption, IEquatable(TValue value) => value is null ? Option.None : Option.Some(value); - public bool IsSome() => this.Match(() => false, (_) => true); + public bool IsSome => this.Match(() => false, (_) => true); /// /// 获取内部的值,如果为则抛出异常 diff --git a/Sanchime.Functional/Products/Options/OptionFunctor.cs b/Sanchime.Functional/Products/Options/OptionFunctor.cs index 94c0e01..eeb66bb 100644 --- a/Sanchime.Functional/Products/Options/OptionFunctor.cs +++ b/Sanchime.Functional/Products/Options/OptionFunctor.cs @@ -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 //: IFunctor +public readonly partial struct Option { - + /// + /// 映射 + /// + /// + /// + /// + public IOption Map(Func mapping) + => this.Match(() => Option.None, value => Option.Some(mapping(value))); + } \ No newline at end of file diff --git a/Sanchime.Functional/Products/Options/Some.cs b/Sanchime.Functional/Products/Options/Some.cs index 897ba0e..c6efb1a 100644 --- a/Sanchime.Functional/Products/Options/Some.cs +++ b/Sanchime.Functional/Products/Options/Some.cs @@ -4,11 +4,13 @@ namespace Sanchime.Functional.Products; /// 状态 /// /// -public readonly struct Some : IOption, IFunctor +public readonly struct Some : IOption { - 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> Map(Func> mapping) + + public IOption Map(Func mapping) => Option.Some(mapping(this.Value)); } diff --git a/Sanchime.Test/Program.cs b/Sanchime.Test/Program.cs index e76d641..429c5eb 100644 --- a/Sanchime.Test/Program.cs +++ b/Sanchime.Test/Program.cs @@ -2,32 +2,33 @@ using Sanchime.Functional.Extensions; using Sanchime.Toolkits; -// Test test = new Test(); -// Console.WriteLine(test.Map((Test x) => {x.Value = 2; return x;}).Value); +void foo(Option 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 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; diff --git a/Sanchime.Toolkits/Basic.cs b/Sanchime.Toolkits/Basic.cs index 2c12695..217aed1 100644 --- a/Sanchime.Toolkits/Basic.cs +++ b/Sanchime.Toolkits/Basic.cs @@ -3,7 +3,6 @@ namespace Sanchime.Toolkits; public static class Basic { - public static void WriteLine(this T @this) { Debug.WriteLine(@this);