8288分类目录 8288分类目录 8288分类目录
  当前位置:海洋目录网 » 站长资讯 » 站长资讯 » 文章详细 订阅RssFeed

函数式编程之-bind函数

来源:本站原创 浏览:104次 时间:2021-12-28

Bind函数

Bind函数在函数式编程中是如此重要,以至于函数式编程语言会为bind函数设计语法糖。另一个角度Bind函数非常难以理解,几乎很少有人能通过简单的描述说明白bind函数的由来及原理。 这篇文章试图通过“人话”来描述bind函数,并通过浅显的实例为零函数式编程语言的开发者揭秘bind函数的作用及用法。

public string GetSomething(int id){   var x = GetFirstThing(id);   if (x != null)   {       var y = GetSecondThing(x);       if(y != null)       {           var z = GetThirdThing(y);           if (z != null)           {               return z;           }       }   }      return null;}

你一定写过类似的代码,估计你也明白这样的代码看起来很丑陋,一层层的判空嵌套打乱了代码的主题结构。 有没法让他变的更优雅?当然你可以通过"early return"的做法,不过这种方式不在我们的讨论范围之内。 这种风格的代码存在一个明显的code smell, GetFirstThing()/GetSecondThing()/GetThirdThing()等方法有可能返回null,我们说return null是一种不真确的做法,相关分析见拒绝空引用异常。使用Optional类型重构如下:

public Optional<string> GetSomething(int id){   var x = GetFirstThing(id);   if (x.HasValue())   {       var y = GetSecondThing(x);       if(y.HasValue())       {           var z = GetThirdThing(y);           if (z.HasValue())           {               return z;           }       }   }   return Optional.None<string>();}

看起来代码结果跟之前一模一样,重构后的代码并没有变得更漂亮。不过现在的GetFirstThing()/GetSecondThing()/GetThirdThing()方法返回值为Optional<string>类型,不再是普通的string类型:

public Optional<string> GetFirstThing(int id){    //...    return Optional.None<string>();}

重构后的这段代码很有意思,我们可以从函数组合的角度来让整个代码段变的更加优雅。 ##组合 这段代码其实做了一件事,那就是通过调用三个函数GetFirstThing()/GetSecondThing()/GetThirdThing()来完成一个业务逻辑。从函数式编程思想的角度出发,我们倾向于把若干个小的函数连接起来,根据以前学过的知识,只有一个输入和一个输出的函数才能连接起来: 他们之所以能够连接是因为这两个函数的签名一致,都拥有一个输入和一个输出。 例如:int -> string, string -> bool就可以组合为int -> bool。 而我们此时拥有的三个函数方法签名如下:

GetFirstThing: int -> Optional<string>GetSecondThing: string -> Optional<string>GetThirdThing: string -> Optional<string>

显然GetFirstThing和GetSecondThing是无法直接连接的,原因是GetFirstThing返回了Optional<string>类型,而GetSecondThing的输入却是一个普通的string类型。如果我们能够在Optional<T>上扩展一个函数,函数接受一个签名为T -> Optional<T>的函数,那么我们就有可能将上面的三个函数串联起来:

public static class Optional{    public static Optional<T> Bind<T>(this Optional<T> input, Func<T, Optional<T>> f)    {        if (input.HasValue())        {            return f(input.Value);        }        return Optional.None<T>();    }}

有了上面这个神奇的bind函数你就可以将上面的三个函数连接起来了:

public string GetSomething(int id){    return GetFirstThing(id).Bind(GetSecondThing).Bind(GetThirdThing);}

用F#实现:

let address = getFirstThing id    |> bind getSecondThing    |> bind getThirdThing

通过bind函数我们成功将三个函数连接了起来, 同时将判空放在了bind函数里,从而保持主要逻辑部分更加线性和清晰。

如何编写属于自己的bind函数
  1. 首先需要定义一个泛型类型E<a>,例如我们上面例子中提到的Optional<T>
  2. 编写属于Optional<T>的bind函数,bind函数的签名为E<a> -> (f: a -> E<b>) -> E<b>。 接收一个E<a>,同时接受一个签名为a -> E<b>的函数,返回E<b>。

List<T>中的bind函数

我们经常用的List<T>就是一个典型的泛型类型,那他上面有没有bind函数?当然有,不过叫做SelectMany, Scala中也叫flatMap。 看一下SelectMany的方法签名,正好符合bind函数的签名要求:

public static IEnumerable<TResult> SelectMany<TSource,TResult>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TResult>> selector){  //...}

SelectMany可以用在什么样的场景中? 例如有这样一个场景,一篇文章(paper)可以有若干章节(section)组成,每个章节(section)又有若干行(row)组成,每行(row)有若干单词(word)组成。

问:给定一篇文章(paper),请找出大于10行(row)的章节(section),里面排除注释的行(row)总共的单词(word)数量。

首先根据需求变下下面的若干函数:

private List<Paper.Section> GetSections(Paper paper){    return paper.Sections.Where(s => s.Rows.Count > 10).ToList();}private List<Paper.Section.Row> GetRows(Paper.Section section){    return section.Rows.Where(r=>!r.IsComment).ToList();}private List<Paper.Section.Row.Word> GetWords(Paper.Section.Row row){    return row.Words;}

且看这三个函数的签名:

GetSections: Papaer -> List<Section>GetRows: Section -> List<Row>GetWords: Row -> List<Word>

正好这就是就符合bind函数连接的需求:

var length = GetSections(paper)            .SelectMany(GetRows)            .SelectMany(GetWords)            .Count();

F#实现:

let words = getSections paper    |> bind getRows    |> bind getWords words.Length

bind函数的语法糖支持

bind函数在函数式编程中如此常见,以至于需要设计单独的语法糖,Haskell中叫do natation, Scala中叫for comprehension,F#用Computation expressions:

list {    let! secti��ǰ�ٺ�,�����þ�on = getSections(paper)    let! row = getRows(section)    let! word = getWord(row)    return word}

  推荐站点

  • At-lib分类目录At-lib分类目录

    At-lib网站分类目录汇集全国所有高质量网站,是中国权威的中文网站分类目录,给站长提供免费网址目录提交收录和推荐最新最全的优秀网站大全是名站导航之家

    www.at-lib.cn
  • 中国链接目录中国链接目录

    中国链接目录简称链接目录,是收录优秀网站和淘宝网店的网站分类目录,为您提供优质的网址导航服务,也是网店进行收录推广,站长免费推广网站、加快百度收录、增加友情链接和网站外链的平台。

    www.cnlink.org
  • 35目录网35目录网

    35目录免费收录各类优秀网站,全力打造互动式网站目录,提供网站分类目录检索,关键字搜索功能。欢迎您向35目录推荐、提交优秀网站。

    www.35mulu.com
  • 就要爱网站目录就要爱网站目录

    就要爱网站目录,按主题和类别列出网站。所有提交的网站都经过人工审查,确保质量和无垃圾邮件的结果。

    www.912219.com
  • 伍佰目录伍佰目录

    伍佰网站目录免费收录各类优秀网站,全力打造互动式网站目录,提供网站分类目录检索,关键字搜索功能。欢迎您向伍佰目录推荐、提交优秀网站。

    www.wbwb.net