zoukankan      html  css  js  c++  java
  • Linq怎么支持Monad

      在上一篇创建了我们的第一个Monad, Identity<T>. 我们确定了类型要变成Monad, 它必须有一个type constructor(Identity<T>), 和两个方法,Bind与ToIdentity

    //a function Bind, allows us to compose Identity returning functions
    
    public static Identity<B> Bind<A,B>(this Identity<A>a, Func<A,Identity<B>func>)
    {
    return func(a.Value);
    }
    
    public static Identity<T>ToIdentity<T>(tis T Value)
    {
    return new Identity<T>(value);
    }

    我也提到了在C#里 Bind有个不同的名字,SelectMany,它是为IEnumerable<T>定义的扩展方法, 如你所知,IEnumerable<T>也是一个Monad,实际上它是C#里Monad的代表.

            今天我们来看下如何为Identity<T>实现SelectMany, 并且去掉繁琐的lambda表达式

    Linq要求我们写一个函数来结合Bind和To****的功能,SelectMany,SelectMany签名必须如下:

    Identity<C>SelectMany<A,B,C>(this Identity<A>a,Func<A,Identity<B>>func,Func<A,B,C>select)

    它看起来像Bind函数,只是多了一个select参数,它以A,B为参数,返回C。 并且有一个不同的返回类型Identity<C>,替代Identity<B>. 如果你的amplified实现了SelectMany方法,在执行Linq的"from x in y"表达式时会转换为SelectMany的调用.

    让我们将SelectMany实现为一个扩展方法:

    public static Identity<C>SelectMany<A,B,C>(this Identity<A>a,Func<A,Identity<B>>func, Func<A,B,C>select)
    {
    return ???
    }

    现在要根据参数类型来写出实现,首先我们知道要返回Identity<C>, 只有select Func可以返回C,我们可以调用ToIdentity将C转换为Identity<C>

    public static Identity<C>SelectMany<A,B,C>(this Identity<A>a,Func<A,Identity<B>>func, Func<A,B,C>select)
    {
    return select(???).ToIdentity();
    }

    传什么给select呢, 第一个参数是A,我们可以调用a.Value得到A, 第二个参数B,我们可以通过Bind函数得到B

    public static Identity<C>SelectMany<A,B,C>(this Identity<A>a,Func<A,Identity<B>>func, Func<A,B,C>select)
    {
    return (a.Value,a.Bind(func).Value).ToIdentity();
    }

    让我们展开Bind函数,在这里Bind并没有多大用

    public static Identity<C>SelectMany<A,B,C>(this Identity<A>a,Func<A,Identity<B>>func, Func<A,B,C>select)
    {
    return select(a.Value,func(a.Value).Value).ToIdentity();
    }

    我们已经为Identity<T>实现了SelectMany. 现在我们可以用Linq语法替换我们上一篇的lambda表达式:

    var result="Hello World!".ToIdentity().Bind(a=>
    
                                           7.ToIdentity().Bind(b=>
    
     (new DateTime(2010,1,11)).ToIdentity().Bind(c=>
    
    (a+", "+b.ToString()+", "+c.ToShortDateString())
    
                                               .ToIdentity())));
    
    var result=from a in "Hello World".ToIdentity()
    
                     from b in 7.ToIdentity()
    
                     from c in (new DateTime(2010,1,11)).ToIdentity()
    
                     select a+", "+b.ToString()+", "+c.ToShortDateString();
    
    Console.WriteLine(result.Value);

    是不是清晰很多?通过新视角看Linq和Monad, 我们可以把"from x in y"看做是Monad式的赋值,将将右侧的amplified value 赋值给左侧的unamplified type。

    实际上你可以对任何WhatEver<T>使用Linq语法,而不仅仅是IEnumerable<T>。如果你想使用其他linq 语法如where,let,join等,你必须实现对应的方法, 他们都可以使用Bind创建

  • 相关阅读:
    字符串与模式匹配算法(一):BF算法
    Spring MVC:HandlerMapping
    Spring MVC:DispatchServlet类
    Spring:面向切面编程的AOP
    Java:检查异常与未检查异常
    AOP源码解析:AspectJExpressionPointcutAdvisor类
    Vue+Webpack打包之后超过url-loader大小限制的图片在css的background-image中使用路径问题
    less
    ES6模块的import和export用法总结
    bootstrap4网格
  • 原文地址:https://www.cnblogs.com/phenixyu/p/5621915.html
Copyright © 2011-2022 走看看