我正在编写一些通用代码,以允许对函数进行基本操作。如果我举一个例子,这可能是最简单的:
julia> import Base: +,^
julia> +(f1::Function,f2::Function) = x -> f1(x)+f2(x)
julia> ^(f1::Function, n::Int) = x -> f1(x)^n
julia> unity = sin^2 + cos^2
julia> unity(123.456)
1.0
到目前为止,一切顺利。现在,假设我注意到我想让第二个参数总是正的,因为一个三角函数的-ve次方意味着一个反函数——一个完全不同的情况。此外,我可能甚至不需要一个很大的值,所以假设我决定将其限制为UInt16。
然而,
julia> ^(f1::Function, n::UInt16) = x -> f1(x)^n
^ (generic function with 67 methods)
julia> unity = (sin^2) + (cos^2)
ERROR: MethodError: no method matching ^(::typeof(sin), ::Int64)
Closest candidates are:
^(::Float16, ::Integer) at math.jl:885
^(::Regex, ::Integer) at regex.jl:712
^(::Missing, ::Integer) at missing.jl:155
...
Stacktrace:
[1] macro expansion at ./none:0 [inlined]
[2] literal_pow(::typeof(^), ::typeof(sin), ::Val{2}) at ./none:0
[3] top-level scope at REPL[4]:1
我不明白MethodError。为什么:
ERROR: MethodError: no method matching ^(::typeof(sin), ::Int64)
期望Int64?更重要的是,我如何克服它,得到我想要的行为?
(PS。只要系统适当地处理类型,并且API用户不必使用虚假的强制类型转换,那么目标就是一种直观且可预测的数学描述语言,其风格类似于以Scheme闻名的Sussman风格。
谢谢!
2 isa Int
(非UInt16
)。值不能有多种类型
问题是,当给定一个整数常量时,Julia的编译器会查看该数字的格式,并根据该格式为其分配一个类型。以10为基数的数字默认为Int (有符号)Int64)和0x123等数字默认为无符号整数类型,用于分配无符号类型大小的常量中使用的位数:0x5和0x05 UInt8, 0x005和0x0005 UInt16,等等。所以:
julia> fpow(f, n::UInt16) = x -> f(x)^n
fpow (generic function with 1 method)
julia> sinpow(x, n) = fpow(sin, n)(x)
sinpow (generic function with 1 method)
julia> sinpow(pi, 5)
ERROR: MethodError: no method matching fpow(::typeof(sin), ::Int64)
Closest candidates are:
fpow(::Any, ::UInt16) at REPL[13]:1
Stacktrace:
[1] sinpow(x::Irrational{:π}, n::Int64)
@ Main .REPL[14]:1
[2] top-level scope
@ REPL[15]:1
julia> sinpow(pi, 0x5)
ERROR: MethodError: no method matching fpow(::typeof(sin), ::UInt8)
Closest candidates are:
fpow(::Any, ::UInt16) at REPL[13]:1
Stacktrace:
[1] sinpow(x::Irrational{:π}, n::UInt8)
@ Main .REPL[14]:1
[2] top-level scope
@ REPL[16]:1
julia> sinpow(pi, 0x005)
0.0
但是Julia会将基数为16的有符号常量更改为无符号常量(2s补码)而没有抱怨。你想这样做吗?它:
julia> sinpow(pi, -0x005)
0.0
因此,我建议,为了避免不必要的错误消息,您可以在函数声明中使用Integer
,并使用@assert()
来要求n >= 0
:
function fpow(f, n::Integer)
@assert n >= 0
return x -> f(x)^n
end
或
fpow(f, n::Integer) = (n >= 0 || error("exponent cannot be < 0"); x -> f(x)^n)