Python和Scala的一等函数

函数指的是执行某个任务或者是一系列的指令被组织成的一片代码块。标准的数学意义上的函数指的是输入集合和输出集合的一种对应关系。

函数 而在Scala和Python里,函数是一等对象,这个得益于它们对于函数的实现都是基于类的函数实例。也就是说,函数本身就是一个对象。Scala的函数都是FunctionN包一个特质的类的实例,例如Function0代表不带参数的函数,Function1代表带一个参数的函数,使用apply方法调用函数。

scala> def sum(a:Int) = a
sum: (a: Int)Int

scala> val a = sum _
a: Int => Int = <function1>

scala> a.apply(1)
res1: Int = 1

scala> a.
andThen        apply          asInstanceOf   compose        isInstanceOf   toString

而Python的函数则是function类的实例。

>>> def sum(a):
...   return a
...
>>> type(sum)
<class 'function'>

作为一等函数,自然有着与众不同之处。在维基里,一等函数是“the language supports passing functions as arguments to other functions, returning them as the values from other functions, and assigning them to variables or storing them in data structures.”翻译过来就是函数是可以赋值给变量或数据结构中的元素,可以作为参数传给函数,可以作为函数的返回结果。这篇文章先不讨论闭包的概念,专注于一等函数的这些性质是如何在Scala和Python里体现出来的。

1.高阶函数 高阶函数在维基的定义是“a function taking another function as argument”,一个函数可以接受函数作为参数。在函数式编程里最为出名的就是map,filter和reduce这三个高阶函数。例如我们可以在Scala里,这么写:

scala> val Numbers = List(0,1,2)
Numbers: List[Int] = List(0, 1, 2)

scala> def equalsZero(x:Int) = {x == 0}
equalsZero: (x: Int)Boolean

scala> Numbers.filter(equalsZero)
res2: List[Int] = List(0)

我们可以把equalsZero作为一个参数传入filter方法里选出列表里等于0的数,生成一个新的列表。同样的Python也是可以实现的:

>>> def equals_zero(x):
...   return x == 0
...
>>> numbers = [0,1,2]
>>> list(filter(equals_zero,numbers))
[0]

因为在Python3里大量使用了生成器,所以我们需要使用list内置函数将filter函数返回的值求出来。

2.匿名函数 严格来说,匿名函数是没有绑定标识符的函数定义,“a function definition that is not bound to an identifier.”。它起源于λ表达式,可以算是函数式编程里面一个很核心的概念了。在Scala里,匿名函数被称为函数字面量,是用圆括号括起来的一组带名字的参数,一个右箭头和函数体。它会在运行时实例化为正常的函数实例。

scala> val add = (x:Int, y:Int) => x+y
add: (Int, Int) => Int = <function2>

scala> add(1,2)
res1: Int = 3

函数字面量也同样的支持类型推断,例如在之前的Numbers.filter可以这么写:

scala> Numbers.filter((x) => x == 0)
res3: List[Int] = List(0)

Scala的编译器知道x必定是整数,因为你是用来过滤一个整数组成的列表,所以Scala可以推断出x是Int类型。进一步我们也可以把括号去掉。

scala> Numbers.filter(x => x == 0)
res4: List[Int] = List(0)

Scala为了更加简化函数字面量,还引入了下画线_作为占位符,用来表示一个或者多个参数。,只要满足每个参数只在函数字面量出现一次就好了。例如:

scala> Numbers.filter(_ == 0)
res5: List[Int] = List(0)

可以这么理解,作为一个“空”,入参被“填”进去了这个“空”。每一次列表的循环, == 0变成了 0 == 0, 1 == 0,2 == 0直到列表结尾。Scala的占位符还做了进一步的引申:

scala> val equalsZero = (_:Int) == 0
filter: Int => Boolean = <function1>

scala> equalsZero(0)
res2: Boolean = true

scala> equalsZero(-1)
res3: Boolean = false

不同于Scala给匿名函数这么多的支持,Python相对来说不怎么建议你使用匿名函数的。Python使用lambda关键字创建匿名函数:

equals_zero = lambda x :x == 0

但是你只能使用纯表达式,不能使用更复杂的赋值和控制结构。Python认为lambda表达式会导致代码的难以阅读,违背了Python易读的特性,所以给匿名函数施加了极大的限制。

在工程中应该尽量避免匿名函数,除非你确认别人可以不依靠函数名就知道你函数的意义(然而这是很难的),虽然Scala给匿名函数提供了这么多的方便,极大地减少你的手指劳累,我依然不建议你使用。

3.部分应用函数 在函数式编程里还有一个核心的概念,就是部分应用函数,它是基于一个已创建的函数,把原函数的某些参数进行了冻结,只接受一部分的参数。 在Scala的实现里,使用了_占位符:

scala> def sum(a:Int,b:Int) = a + b
sum: (a: Int, b: Int)Int

scala> val a = sum(_:Int,2)
a: Int => Int = <function1>

scala> a(1)
res6: Int = 3

而Python则需要内置库的functools模块的partial。

>>> def sum(a,b):
...   return a + b
...
>>> from functools import partial
>>> a = partial(sum,2)
>>> a(3)
5

原文发布于微信公众号 - 鸿的学习笔记(shujuxuexizhilu)

原文发表时间:2018-03-18

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Python爱好者

Java基础笔记08

1335
来自专栏Kevin-ZhangCG

排序算法总结

1793
来自专栏从流域到海域

《Java程序设计基础》 第7章手记

本章主要内容 - 类的私有成员与公共成员 - 方法的重载 - 构造方法 - 类的静态成员 - 对象的应用 本节课知识性内容很多,这里...

1849
来自专栏锦小年的博客

python学习笔记3.1-函数

在了解了数据结构之后,就需要编写函数了,函数是最常用的封装代码的方式,将具有特殊功能的代码封装成一个函数,不仅可以多次重复调用,减小编程量,同时还能够使我们的代...

2198
来自专栏Flutter入门

Kotlin中apply,run,let,also,with函数总结

run函数和apply函数很像,只不过run函数是使用最后一行的返回,apply返回当前自己的对象。

2112
来自专栏较真的前端

关于数据类型转换的面试题总结

2485
来自专栏Albert陈凯

Scala之偏函数Partial Function

http://blog.csdn.net/bluishglc/article/details/50995939 从使用case语句构造匿名函数谈起 在Scal...

3309
来自专栏LeetCode

LeetCode 169. Majority Element

思路:数组中有一个数字的出现次数超过一半,也就是说这个数字的出现次数比其他的所有的数字的出现次数之和还要多。因此我们可以考虑遍历数组的时候保存两个值,一个是数组...

1301
来自专栏Brian

C++11基础学习系列二

---- 概述 在C++11基础学习系列一中介绍一些c++11一些基础知识。基础学习系列二进一步讲解C++11. string string不可思议,在C++中...

2625
来自专栏老九学堂

弱鸡别走,指针让你更强壮!

指针可以加上或减去一个整数。指针的这种运算的意义和通常的数值的加减运算的意义是不一样的,以单元为单位。例如:

1162

扫码关注云+社区

领取腾讯云代金券