【函数式编程】(六.plus)LINQ查询表达式 如何让我们的代码变得更加优雅?

在我们C#之中,一直有一个与C#风格格格不入的语法,也就是LINQ的查询表达式,如果你没见过的话,这是他的写法

int[] numbers = [ 0, 1, 2, 3, 4, 5, 6 ];
var numQuery = from num in numbers
               where (num % 2) == 0
               select num;

图片

这怎么长的和SQL语句似的?

是的,查询语法其中之一的目的就是为了与SQL保持更一致的查询体验。不过还是有很多人更喜欢扩展方法式的写法

int[] numbers = [ 0, 1, 2, 3, 4, 5, 6 ];
var numQuery = numbers.Where(num => num % 2 == 0);

非常简洁好懂,更多C#程序员会喜欢扩展方法的LINQ也很合理。
查询表达式在C#代码中可能会显得异常突出,不和谐,不过其强大的查询能力依然非常有用,除此之外
查询表达式其实还另有妙用。

(在开始之前,请安装LanguageExt库)
上一期我们介绍了应用式, 学习了如何利用应用式,处理高级界域下的多参函数,不过其实我们同时也介绍了一种,通过单子流(嵌套的bind)来实现的方式,不过那种方式由于复杂的嵌套,不被我们喜欢。
但是若是说我们有办法避免这个嵌套呢?
事实上from对应的是Linq中的selectmany方法,而select则当然对应的是select方法。我们可以写出这样那样的代码

int[] seq = [1, 2, 3, 4, 5];
var seqEven = 
    from x in seq // selectmany
    from x2 in seq // selectmany
    from x3 in seq // selectmany
    from x4 in seq // selectmany
    where x % 2 == 0 // where
    select (x + 1, 2); // select

这段代码的from其实就类似以下实现

var seqEven1 = seq
    .SelectMany(x => seq.SelectMany(x2 => seq));

在最之前我们说过,bind与selectmany的函数签名是完全一致的!

那么事实上,我们当然也可以对bind做类似的事情。这下我们回头一看发现,查询表达式的语法,居然是不受语法嵌套限制的!这就弥补了我们之前不满意的一点,我们可以将代码写成

var v4 = 
    from x in GetSome(6)
    from y in GetSome(x - 3)
    select Add(x, y);

int Add(int a, int b) => a + b;
Either<string, int> GetSome(int value)
{
    Console.WriteLine("+++" + value);
    return value > 4 ? value : "Too Small";
}

对比原来的写法

var v1 = GetSome(1);
var v2 = GetSome(6);
// v1 + v2 使用Add函数
var v3 = v1
    .Bind(v1v => // SelectMany
       v2.Map(v2v => v1v + v2v) // Select
    );

曾经麻烦的嵌套bind在查询表达式的协助下变得非常优雅,我们可以轻易的取出其中的内容,并在有失败内容的时候整个表达式就会快速失败(与之前的bind行为一致),我们称之为单子流

在普通的编程模式中,我们遇到的比较多的高级值可能就是类似数组这类,大多数时候我们用Linq方法就能轻松解决其查询问题,但是在函数式编程中我们将会运用到一堆的高级值的时候,查询表达式的优点就被明显的放大了!这就是查询表达式语法的妙用(不过在F#中 我们拥有计算表达式可以更好的实现这一点)

那么应用式单子流有什么差异呢,如果我们使用查询表达式的单子流似乎把原有应用式一些仅有的优点都覆盖了?

事实上还是有区别的

应用式中所有的参数计算已经完成,可以只是单纯的组合。并且参数也可以分别的并行的计算出来,较为独立,不能互相依赖,但是可以一次性收集所有参数的错误。(这在后面验证器中可能会非常有用)

单子流,(正如代码所示)可以依赖于上一个计算的结果,并且一定程度上不依赖于柯里化,不过也由于其快速失败的特性,所以我们没法方便的收集到所有可能的问题。

这下我们就了解了函数式编程中两种应对多参函数的方法,掌握他们,让他们在正确的地方上发挥自己的作用吧!

学会了吗?学会了

Bilibili: @无聊的年 【C#】【函数式编程6.plus】C#中Linq查询表达式存在的目的是什么?它能让我们的代码更优雅吗?_哔哩哔哩_bilibili应用式与多参函数, 视频播放量 1963、弹幕量 3、点赞数 45、投硬币枚数 12、收藏人数 51、转发人数 2, 视频作者 无聊的年, 作者简介 今天是学习.NET的好日子 | Microsoft MVP,相关视频:【C#邪道】《string是只读的》,切忌 SELECT ,就算表只有一列,如何在视图模型(ViewModel)中管理一个异步任务,1、编程思想介绍(重要),你不知道的C#冷知识(其四),Rx.NET响应式编程入门,借助ObservableCollections包实现具备通知功能的多种集合类型,【.NET10】【C#14】.NET10预览版3/C#14新语法速览,我确实错了,Linus是对的,之所以不用C++是因为:任何内存不透明的编译器或者语言,都不是操作系统内核理想的编程语言,“冷门“编程语言C# 为什么能够逆势上涨 ?https://www.bilibili.com/video/BV1rGMdzcEpn/?spm_id_from=333.1387.homepage.video_card.click

微信公众号: @scixing的炼丹房

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值