为什么不能在Julia函数签名中指定类型(UInt) ?



我正在编写一些通用代码,以允许对函数进行基本操作。如果我举一个例子,这可能是最简单的:

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)

相关内容

最新更新