hypot1 = function(x,y){
x = abs(x)
y = abs(y)
if(x > y) {
r = y/x
return(x*sqrt(1+r^2))
}
if(y == 0) {
return(zero(x))
}
r = x/y
return(y*sqrt(1+r^2))
}
hypot1(3,4)
import numpy as np
def hypot1(x,y):
x = abs(x)
y = abs(y)
if x>y:
r = y/x
return x*np.sqrt(1+r**2)
if y==0:
return zero(x)
r = x/y
return y*np.sqrt(1+r**2)
hypot1(3,4)
function hypot1(x,y)#::Int16
x = abs(x)
y = abs(y)
if x > y
r = y/x
return x*sqrt(1+r*r)
end
if y==0
return zero(x)
end
r = x/y
return y*sqrt(1+r*r)
end
hypot1(3,4)
x = (a=1, b=1+1)
x.a
Python元组没有此功能
x = (a=1, b=1+1)
R中没有tuple
这种数据结构,( )
同c
相结合c( )
用来定义最普通的数组
c(1,2,3)
如果一个函数的参数被写成了元组形式 (如 (x, y)) 而不是简单的符号,那么一个赋值运算 (x, y) = argument 将会被默认插入:
minmax(x, y) = (y < x) ? (y, x) : (x, y)
range((min, max)) = max - min
range(minmax(10, 2))
通过在最后一个参数后面增加一个省略号来定义一个变参函数:
bar(a,b,x...) = (a, b, x)
变量 a 和 b 和以前一样被绑定给前两个参数,后面的参数整个做为迭代集合被绑定到变量 x 上, 在所有这些情况下,x 被绑定到传递给 bar 的尾随值的元组:
bar(1,2)
bar(1,2,3)
bar(1,2,3,4,5)
另一方面,将可迭代集中包含的值拆解为单独的参数进行函数调用通常很方便。 要实现这一点,需要在函数调用中额外使用 ... 而不仅仅只是变量:
x = (3,4)
bar(1,2,x...)
bar(1,2,x)
在这个情况下一组值会被精确切片成一个可变参数调用,这里参数的数量是可变的。
x = (2,3,4)
bar(1,x...)
x = (1,2,3,4)
bar(x...)
进一步,拆解给函数调用中的可迭代对象不需要是个元组:
x = [1,2,3,4]
bar(x...)
另外,参数可拆解的函数也不一定就是变参函数 —— 尽管一般都是:
baz(a,b) = a + b
args = [1,2]
baz(args...)
如果要拆解的容器(比如元组或数组)元素数量不匹配就会报错,和直接给多个参数报错一样
args = [1,2,3]
baz(args...)
某些函数需要大量参数,或者具有大量行为。记住如何调用这样的函数可能很困难。关键字参数允许通过名称而不是仅通过位置来识别参数,使得这些复杂接口易于使用和扩展。
请注意,这样做有两个目的。调用更可读,因为我们能以其意义标记参数。也使得大量参数的任意子集都能以任意次序传递。另外,关键字参数必须指定默认值
具有关键字参数的函数在签名中使用分号定义:
function plot(x, y; style="solid", width=1, color="black")
###
end
关键字参数的类型可以通过如下的方式显式指定:
function f(;x::Int=1)
###
end
附加的关键字参数可用 ... 收集,正如在变参函数中:
function f(x; y=0, kwargs...)
###
end
如果一个关键字参数在方法定义中未指定默认值,那么它就是必须的:如果调用者没有为其赋值,那么将会抛出一个 UndefKeywordError 异常:
function f(x; y)
###
end
f(3, y=5) # ok, y is assigned
f(3) # throws UndefKeywordError(:y)
在 f 内部,kwargs 会是一个具名元组。具名元组(以及字典)可作为关键字参数传递,通过在调用中使用分号,例如 f(x, z=1; kwargs...)。
在分号后也可传递 key => value 表达式。例如,plot(x, y; :width => 2) 等价于 plot(x, y, width=2)。当关键字名称需要在运行时被计算时,这就很实用了。
Python的函数定义中没有;以示区别
def f(x,y,alpha = 0.05):
return alpha*(x**2+y)
f(2,3, alpha = 0.02)
R的函数定义中也没有;
以示区别
另外,R同Python一个区别就是,关键字参数在之后调用时其位置没有Python那么严格,需要一一对应,可以任意放
f <- function(x, y, alpha = 0.05) {
alpha*(x^2+y)
}
f(alpha = 0.02,2,3)
当计算可选和关键字参数的默认值表达式时,只有先前的参数才在作用域内。例如,给出以下定义:
# a=b 中的 b 指的是外部作用域内的 b,而不是后续参数中的 b。
function f(x, a=b, b=1)
x+a+b
end
f(2)
def f(x, a = b, b=1):
x+a+b
f(2)
但R的作用域是基于Lexical Scoping,当a没有直接定义而b定义时,它会根据a=b
将b的值域给a
f = function(x, a=b, b=1) {
x+a+b
}
f(2)
把函数作为参数传递给其他函数是一种强大的技术,比如三种语言都有的map/Map
函数,R语言中的apply
系列函数,当函数参数占据多行时,直接通过匿名函数调用便特别难以编写,例如调用map
函数:
map(x -> begin
if x < 0 && iseven(x)
return 0
elseif x == 0
return 1
else
return x
end
end,
[-2,0,2])
使用保留字do
重写此代码:
map([-2,0,2]) do x
if x < 0 && iseven(x)
return 0
elseif x == 0
return 1
else
return x
end
end
lapply(c(-2,0,2),function(x) {
if(x<0 && (x%%2 == 0)) {
return(0)
}
if(x == 0) {
return(1)
} else {
return(x)
}
})
Map(function(x) {
if(x<0 && (x%%2 == 0)) {
return(0)
}
if(x == 0) {
return(1)
} else {
return(x)
}
}, c(-2,0,2))