首页 > 解决方案 > Julia typeof 的令人费解的结果

问题描述

typeof对 Julia 1.0.0 REPL 中的以下结果感到困惑:

# This makes sense.   
julia> typeof(10)
Int64

# This surprised me.
julia> typeof(function)
ERROR: syntax: unexpected ")"

# No answer at all for return example and no error either.
julia> typeof(return)

# In the next two examples the REPL returns the input code.    
julia> typeof(in)
typeof(in)

julia> typeof(typeof)
typeof(typeof)

# The "for" word returns an error like the "function" word.
julia> typeof(for)
ERROR: syntax: unexpected ")"

Julia 1.0.0文档typeof “获取 x 的具体类型”。

这个typeof(function)例子真的让我感到惊讶。我希望 afunction成为 Julia 中的一流对象并具有类型。我想我需要了解 Julia 中的类型。

有什么建议么?

编辑

根据下面的一些评论问题,这是一个基于小函数的示例:

julia> function test() return "test"; end
test (generic function with 1 method)

julia> test()
"test"

julia> typeof(test)
typeof(test)

基于这个例子,我本来希望typeof(test)返回generic function,而不是typeof(test)

标签: julia

解决方案


需要明确的是,我不是 Julia 内部的铁杆用户。下面是一个旨在(希望)为非核心用户直观地解释 Julia 中的功能的答案。我确实认为这个(非常好的)问题也可以从该语言更核心的开发人员之一提供的更具技术性的答案中受益。此外,这个答案比我想要的要长,但我使用了多个示例来尝试使事情尽可能直观。

正如评论中所指出的,function它本身是一个保留关键字,本身并不是一个实际的函数因此与实际问题正交。该答案旨在解决您对该问题的编辑。

由于 Julia v0.6+Function是一个抽象超类型,与抽象超类型非常相似Number。所有函数,例如mean用户定义函数和匿名函数,都是 的子类型Function,与Float64Int的子类型一样Number

这种结构是经过深思熟虑的,并且有几个优点。

首先,由于我不完全理解的原因,以这种方式构造函数是允许 Julia 中的匿名函数与来自Base. 如果您想了解更多相关信息,请参阅此处此处作为起点。

其次,因为每个函数都是它自己的子类型,你现在可以在特定的函数上进行调度。例如:

f1(f::T, x) where {T<:typeof(mean)} = f(x)

和:

f1(f::T, x) where {T<:typeof(sum)} = f(x) + 1

是函数的不同调度方法f1

那么,考虑到这一切,为什么会typeof(sum)返回typeof(sum),尤其是考虑到typeof(Float64)返回DataType?这里的问题是,粗略地说,从句法的角度来看,sum需要同时服务于两个目的。它需要同时是一个值,例如1.0,尽管它是用于sum在某些输入上调用函数的值。但是,它也需要是一个类型名称,例如Float64.

显然,它不能同时做到这两点。所以sum它本身的行为就像一个值。你可以写f = sum ; f(randn(5))来看看它是如何表现得像一个值的。但是我们还需要某种表示类型的方法,sum它不仅适用于sum,而且适用于任何用户定义的函数和任何匿名函数。开发人员决定使用(可以说)最简单的选项,并将sumprint 的类型从字面上看为typeof(sum),因此您观察到的行为。同样,如果我写f1(x) = x ; typeof(f1),那也将返回typeof(f1)

匿名函数有点棘手,因为它们不是这样命名的。我们应该做什么typeof(x -> x^2)?实际发生的情况是,当您构建匿名函数时,它会作为临时全局变量存储在模块Main中,并给出一个数字作为其类型以用于查找目的。所以如果你写f = (x -> x^2),你会得到类似的东西#3 (generic function with 1 method),并且typeof(f)会返回类似的东西getfield(Main, Symbol("##3#4")),在那里你可以看到Symbol("##3#4")这个匿名函数的临时类型存储在Main. (这样做的一个副作用是,如果您编写的代码一遍又一遍地任意生成相同的匿名函数,您最终会溢出内存,因为它们实际上都被存储为它们自己类型的单独全局变量 - 但是,这确实不会阻止您for n = 1:largenumber ; findall(y -> y > 1.0, x) ; end在函数内部执行此类操作,因为在这种情况下,匿名函数仅在编译时编译一次)。

将所有这些都与Function超类型相关联,您会注意到 return typeof(sum) <: Functiontrue表明sumakatypeof(sum)的类型确实是 的子类型Function。还要注意typeof(typeof(sum))return DataType,其方式与 return 非常typeof(typeof(1.0))相似DataType,它显示了sum实际行为如何像一个值。

现在,鉴于我所说的一切,您问题中的所有示例现在都有意义。typeof(function)并按typeof(for)应有的方式返回错误,因为functionfor是保留的语法。typeof(typeof)andtypeof(in)正确返回(分别)typeof(typeof), and typeof(in), 因为typeofandin都是函数。当然要注意typeof(typeof(typeof))返回DataType


推荐阅读