前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >4 函数 方法 多重分派

4 函数 方法 多重分派

作者头像
猫叔Rex
发布2020-06-30 14:27:09
5370
发布2020-06-30 14:27:09
举报
文章被收录于专栏:科学计算

函数和方法

函数

函数定义

代码语言:javascript
复制
function f1(x,y)
    x + y   # 可以不带return,当然也可以写成return x + y
end
>>f (generic function with 1 method)
f(1,2)
>>3

函数的最后一行是不需要加return的,return一般用于在函数中间返回时使用。因为Julia的代码都是表达式(在后面的元编程一节中会讲到),表达式是有返回值的,要么是nothing,要么是别的,因此函数最后一行默认就是返回值,无需再加return;如果一个函数不想有返回值,那再最后一行写个nothing即可。

可以指定函数输出的类型

代码语言:javascript
复制
function g(x, y)::Int8
           return x * y
end
typeof(g(2,3))
>>Int8

符号也可以当做函数使用

代码语言:javascript
复制
+(1,2,3)
>>6
f2 = +
f2(1,2,3)
>>6

给函数添加说明

代码语言:javascript
复制
"simple add function"
function funcAdd(x, y)
    x + y
end

使用@doc funcAdd可以看到函数前的注释,如果是在REPL中定义的函数,则可以在help模式下查看函数使用说明

匿名函数

代码语言:javascript
复制
map(x->x*2 + 1, [1,2,3,4])
>>4-element Array{Int64,1}:
 3
 5
 7
 9

多返回值

代码语言:javascript
复制
function f3(x,y)
    x+y, x-y
end
f3(3,4)    
>>(7,-1)  #返回的是一个tuple
minVal(x,y) = (x < y) ? x : y;

可变参数

代码语言:javascript
复制
function f4(x...)
    r1 = length(x)
    r2 = x[r1]
    return r1,r2
end
println(f4(4,6,9))
>>(3,9)
println(f(11,15,(18,20)))
>>(3, (18,20))

默认参数 关键字参数

代码语言:javascript
复制
function f5(x,y=1)
   return  x + y
end
f5(3)
f5(5,6)
f5(x=7,y=8)

function f6(x;y,z=3)
   return  x + y + z
end
f6(3,y=5)
f6(4,y=3,z=8)

参数类型 Julia虽然属于动态语言,但函数定义时可指定其参数类型

代码语言:javascript
复制
function f7(x::Int8)
    x + 3
end
f7(Int8(10))

函数的其他使用方法

map

代码语言:javascript
复制
function funcAbs(x)
    x >=0 ? x : -x
end
map(funcAbs, -3:3)

reduce

代码语言:javascript
复制
fucntion add(x, y)
    x + y
end
reduce(add, 1:10)
>>55
reduce(+, 1:10)
>>55

|>操作符,对于运算顺序非常直观

代码语言:javascript
复制
"abcde" |> uppercase
[i for i in 1:5] |> join

当然,Julia中函数还有更简单灵活的定义方式

代码语言:javascript
复制
f8(x::Int64,y::Int64) = 2*x + y
f8(4,3)
>>11

看到这里,是不是更加喜欢Julia了!它就是这么简洁明了。

方法

函数和方法的区别

同样的函数,可以有不同的方法,比如加法函数,可以实现整数加法,浮点数加法和复数加法等,他们都是实现加法功能,即他们是同一个函数,但他们的实现方法不一样,可以理解位C++中的重载。 在REPL上可以看到我们定义的函数有几种方法。Julia会选择更加专用的那一个方法。

代码语言:javascript
复制
function f9(x::Int64, y::Int64)
    x + y   
end
>>f9 (generic function with 1 method)

表示该函数只有一个方法

如果我们再定义一个f9,参数类型位Float64

代码语言:javascript
复制
function f9(x::Float64,y::Float64)
    x + y   
end
>>f9 (generic function with 2 methods)

这时当我们执行f(2,3)编译器会自动选择更加专用的方法来执行,也就是第一个方法。

我们也可以直接输入+看到加号(也是一个函数)的方法数

代码语言:javascript
复制
+
>>+ (generic function with 170 methods)

可以使用methods(f9)来看f9的具体方法

但如果两个方法都不更加专用,就会出现分歧。

代码语言:javascript
复制
g(x::Int64, y) = 2x + y
g(x, y::Int64) = x + 2y
g(2,3.0)
>>7.0
g(2.0,3)
>>8.0

但如果是g(2,3),那两个方法没有更加专用的,这时就会报error,解决方法就是定义一个更加专用的方法:g(x::Int64, y::Int64)

参数方法

我们先定义一个简单的方法,对于任何输入,结果都是false

代码语言:javascript
复制
f10(x,y) = false
f10(1,2)
>>false

再增加一个方法

代码语言:javascript
复制
f10(x::T, y::T) where {T} = true
f10(1,2)
>>true
f10(1,2.1)
>>false

第二个方法的意思是当两个参数的类型相同时,返回true

当然,这种方式还可以针对矩阵进行操作

代码语言:javascript
复制
f11(v::Vector{T}, x::T) where {T} = [v..., x]
f11([1,2,3],4)
>>4-element Array{Int64,1}:
 1
 2
 3
 4
f11([1,2,3],4.2)
>>ERROR: MethodError

还可以对子类型参数进行约束

代码语言:javascript
复制
f12(x::T, y::T) where {T<:Number} = true

多重分派

分派就是指根据变量的类型选择相应的方法,单分派指的是指根据第一个参数类型去选择方法。

下面我们举一个Python中的例子,Python因为在函数定义时是不知道参数类型的,所以一般没有单分派;但Python中提供了单分派的修饰符,可以实现单分派的功能。

代码语言:javascript
复制
from functools import singledispatch

@singledispatch
def func(arg, verbose=False):
    print('initial...\n')

@func.register(int)
def _(arg, verbose=False):
    print(arg)

func(1)
>>1
func(2.3)
>>initial...

可以看出,函数func()的结果只跟第一个参数的类型有关,跟后面的参数没有关系,这就是单分派。

使用函数的所有参数,而非只用第一个,来决定调用哪个方法被称为多重分派。多重分派对于数学代码来说特别有用,人工地将运算视为对于其中一个参数的属于程度比其他所有的参数都强的这个概念对于数学代码是几乎没有意义的:x + y 中的加法运算对 x 的属于程度比对 y 更强?一个数学运算符的实现普遍基于它所有的参数的类型。即使跳出数学运算,多重分派是对于结构和组织程序来说也是一个强大而方便的范式。

优化方法的使用

  • 只根据一个参数分派

Julia是多重分派的模式,那如果我们在定义方法的时候想只根据第一个参数分派怎么办?我们可以采用“名字级联”的方式,在内部做好分派。例如我们可以采用下面的方式:

代码语言:javascript
复制
f(x::A, y) = _fA(x, y)
f(x::B, y) = _fB(x, y)

这样对于函数f()来说,只根据第一个参数就可以进行分派了。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-05-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 傅里叶的猫 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 函数和方法
    • 函数
      • 方法
        • 多重分派
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档