6.5.1 函数组合

处理函数最重要的操作,就是组合。先看一个示例是非常有用的,这个示例用元组保存(城市的)名字和人口。在清单 6.16 中,我们创建一个函数,根据人口的规模,确定是城市、镇,还是村;同时用保存在列表中的几个地方测试确定状态。

清单 6.16 处理城市信息 (F# Interactive)

> let places = [("Grantchester", 552);    <-创建测试数据列表

("Cambridge", 117900);

("Prague", 1188126); ];;

val places : (string * int) list

> let statusByPopulation(population) =    <- 根据人口返回状态

matchpopulation with

|n when n > 1000000 -> "City"

|n when n > 5000 -> "Town"

|_ -> "Village";;

val statusByPopulation : int –> string

> places |> List.map (fun (_,population) –>   [1] <- 迭代地方,读人口信息

statusByPopulation(population));;    [2] <- 计算状态

val it : string list =["Village"; "Town"; "City"]

清单 6.16 的第一部分(创建了测试数据的列表,声明 statusByPopulation 函数)非常简单,重要的在最后几行。我们想使用 List.map 获取每个地方的状态,因此,把 lambda 函数作为参数值传递它。lambda 函数首先使用模式匹配[1],从元组中提取第二个元素,然后,调用 statusByPopulation 函数[2]。

代码虽然能够运行,但还可以写得更优雅。关键的思想是,必须依次执行两个运算首先要访问元组中的第二个元素,然后,用返回的值进行计算。第一个运算可以使用 snd 函数实现,因此,需要组合两个函数。在 F# 中,这可以使用函数组合运算符(>>)来写,像这样:

snd >> statusByPopulation

这个运算的结果是函数,参数为元组,读元组的第二个元素(必须是整数),根据这个数计算出城市的状态。看一下表 6.1,我们可以了解函数是如何组合的,表显示了函数的类型签名。

表 6.1 类型签名:snd,statusByPopulation,和通过使用 >> 运算符组合两个函数获得的函数


函数值


类型


snd

snd (after specification)

statusByPopulation

snd >> statusByPopulation


(‘a * ‘b) -> ‘b

(‘a * int) -> int

int -> string

(‘a * int) –> string

表格的第二行表明了 snd 函数的特定类型,编译器推断出元组的第二个元素必须是整数;如果我们把第一行中的类型参数 ‘ b 用 int 类型替换,就得到这个类型。现在,我们有了两个可以组合的函数,因为,第二行函数的返回类型与第三行函数的输入类型相同;通过组合,可以把这两个函数连接到一起,得到的函数,调用第一个函数,并把这个调用的结果传递给第二个函数,最终函数的输入类型与第二行函数相同,返回类型与第三行函数相同。清单 6.17 显示了用函数组合重写原来的代码。

清单 6.17 使用函数组合运算符 (F# Interactive)

> places |> List.map (fun x ->(snd >> statusByPopulation) x);; [1]

val it : string list =["Village"; "Town"; "City"]

> places |> List.map (snd >>statusByPopulation);;  [2]

val it : string list =["Village"; "Town"; "City"]

第一行[1]显式调用组合函数,把包含城市名和人口的元组作为参数值。这演示了组成的结果是函数,可以使用普通的语法来调用;然而,使用函数组合的原因是能够把组合函数作为给其他函数的参数值来使用。这里,组合函数的参数为元组,返回字符串,因此,我们可以直接把它作为 List.map 的参数值来使用,得到样本地点状态的列表[2]。

函数组合运算符的实现非常简单;如果F# 库中不存在这个运算符,我们自己也可以定义它:

> let (>>) f g x = g(f(x))

val (>>) : (‘a -> ‘b) -> (‘b-> ‘c) -> ‘a -> ‘c

在这个声明中,运算符有三个参数。我们早先使用时,只指定前两个参数(函数被组合要。更深入了解组合函数的工作原理,可以看一下图 6.2 中对类型签名的两种可能解释。

图 6-2 函数组合运算符的类型签名。如果指定三个参数值(上面的注释),依次返回调用的结果;如果只指定两个参数值(下面的注释),返回组合函数。

这个运算符之所以能够组合函数,是因为有了散应用。如果只指定前两个参数值,结果是组合函数,当运算符接收第三个参数值时,就使用这个参数值调用第一个函数,然后,使用这个结果去调用第二个函数。很明显,如果指定所有三个参数值,通常没有多大用处,因为我们能够直接调用函数,不必使用这个运算符!

我们已经了解 F# 中函数组合的工作原理,现在,就让我们看一下在 C# 中会是怎样。

时间: 2024-10-10 06:45:25

6.5.1 函数组合的相关文章

Scalaz(14)- Monad:函数组合-Kleisli to Reader

Monad Reader就是一种函数的组合.在scalaz里函数(function)本身就是Monad,自然也就是Functor和applicative.我们可以用Monadic方法进行函数组合: 1 import scalaz._ 2 import Scalaz._ 3 object decompose { 4 //两个测试函数 5 val f = (_: Int) + 3 //> f : Int => Int = <function1> 6 val g = (_: Int) *

index+small+row+if经典函数组合应用

EXCEL中index+small+row+if 函数组合可以查出满足同一条件的所有记录,通过实例讲解: 本文为原创,转载需标明出处,谢谢! 例:查找出一年级的所有班级及人数: A B C D 1 年级 班级 人数 2 一年级 二班 36 3 一年级 三班 38 4 二年级 一班 39 5 一年级 一班 41 6 二年级 三班 38 7 三年级 一班 42 8 三年级 三班 37 9 一年级 四班 40 第一步:IF($B$2:$B$9="一年级",ROW($2:$9),10^10):

F# 可以把几个函数组合成新函数

C#能做的,F#基本都能做,但F#能做的,C#未必能做. F#中的函数可以把几个函数组合起来使用.下面的例子是把由 function1 和 function2 这两个函数通过运算符“>>”(或“<<”)组合而成funuoction3,然后可以拿function3使用. let function1 x = x + 1 let function2 x = x * 2 let function3 = function1 >> function2 let result5 = f

6.5.2 C# 中的函数组合

C# 中的函数组合是可能的,但使用非常有限,这是部分是由于在 C# 中散应用不能很容易使用,但更重要的是,因为大多数操作是用成员来写的,而不是函数.但我们至少可以用 C# 演示同样的想法,清单 6.18 显示了 Compose 方法的实现,以及使用的示例. 清单 6.18实现并使用 Compose 方法 (C#) static Func<A, C> Compose<A, B,C>(this Func<A, B> f, Func<B, C> g) { retu

[Java 8] (10) 使用Lambda完成函数组合,Map-Reduce以及并行化

Java 8中同时存在面向对象编程(OOP)和函数式编程(FP, Functional Programming)这两种编程范式.实际上,这两种范式并不矛盾,只是着重点不同.在OOP中,着重于通过丰富的类型系统对需要解决的问题进行建模:而FP中则着重于通过高阶函数和Lambda表达式来完成计算.所以我们完全可以将这两者融合在一起,对问题提出更加优雅的解决方案. 在这篇文章中,会介绍如何通过函数组合(Function Composition)来将若干个函数单元组合成一个Map-Reduce模式的应用

JS函数式编程【译】4.2 函数组合

?? Functional Programming in Javascript 主目录第四章 在Javascript中实现函数式编程的技术 函数组合 终于,我们到了函数组合. 在函数式编程中,我们希望一切都是函数,尤其希望是一元函数,如果可能的话.如果可以把所有的函数转换为一元函数, 将发生神奇的事情. 一元函数是只接受单个输入的函数.函数如果有多个输入就是多元的,不过我们一般把接受两个输入的叫二元函数, 把接受三个输入的叫三元函数. 有的函数接受的输入的数量并不确定,我们称它为可变的. 操作函

scala进阶:函数组合器(combinator)

collection基础参见之前的博文scala快速学习(二). 本文主要是组合器(combinator),因为在实际中发现很有用.主要参考:http://www.importnew.com/3673.html List(1,2,3) map squared会在列表的每个元素上分别应用squared函数,并且返回一个新的列表,可能是List(1,4,9).我们把类似于map这样的操作称为组合器. 特点:组合器的参数都是一个函数,这个函数的输入输出都是列表元素.最常见的方式是匿名函数用=>定义,左

函数组合的 N 种模式

随着以函数即服务(Function as a Service)为代表的无服务器计算(Serverless)的广泛使用,很多用户遇到了涉及多个函数的场景,需要组合多个函数来共同完成一个业务目标,这正是微服务"分而治之,合而用之"的精髓所在.本文以阿里云函数计算为例,试图全面介绍函数组合的常见模式和使用场景,希望有助于选择合适的解决方案. 虽然本文主要介绍的是函数组合,但是基本思想也可用于服务组合. 函数同步调用函数 在这种模式里,函数直接调用 InvokeFunction 同步 API

函数组合子

List(1, 2, 3) map squared对列表中的每一个元素都应用了squared平方函数,并返回一个新的列表List(1, 4, 9).我们称这个操作map 组合子. 他们常被用在标准的数据结构上. map: map对列表中的每个元素应用一个函数,返回应用后的元素所组成的列表. scala> numbers.map((i: Int) => i * 2) res0: List[Int] = List(2, 4, 6, 8) 或传入一个部分应用函数 scala> def time