我对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 ")"
对于typeof
,Julia1.0.0 documentation说“获取x的具体类型”。
typeof(function)
示例是真正让我惊讶的示例。我希望function
是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)
。
发布于 2018-09-16 19:11:00
需要说明的是,我并不是Julia内部机制的铁杆用户。下面的答案旨在(希望)直观地解释Julia中为非铁杆用户提供了哪些功能。我确实认为这个(非常好的)问题也可以从该语言的核心开发人员提供的更具技术性的答案中受益。此外,这个答案比我希望的要长,但我已经使用了多个示例来尝试使事情尽可能直观。
正如评论中所指出的,function
本身是一个保留的关键字,本身并不是一个实际的函数,因此与实际问题是正交的。此答案旨在解决您对该问题的编辑。
由于Julia v0.6+,Function
是一个抽象的超类型,就像Number
是一个抽象的超类型一样。所有函数,例如mean
、用户定义函数和匿名函数,都是Function
的子类型,就像Float64
和Int
是Number
的子类型一样。
这种结构是经过深思熟虑的,有几个优点。
首先,出于我不完全理解的原因,以这种方式构造函数是允许Julia中的匿名函数像Base
中的内置函数一样快运行的关键。如果您想了解更多关于这方面的知识,请参阅here和here作为起点。
其次,因为每个函数都是它自己的子类型,所以现在可以对特定的函数进行调度。例如:
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
类型。开发人员决定采用(可以说是)最简单的方法,并将sum
类型打印为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
超类型联系起来,您将注意到typeof(sum) <: Function
返回true
,这表明sum
的类型,也就是typeof(sum)
,确实是Function
的一个子类型。还要注意,typeof(typeof(sum))
返回DataType
的方式与typeof(typeof(1.0))
返回DataType
的方式非常相似,这说明了sum
实际上是如何像一个值一样工作的。
现在,考虑到我所说的所有内容,您问题中的所有示例现在都有意义了。typeof(function)
和typeof(for)
按其应有的方式返回错误,因为function
和for
是保留语法。typeof(typeof)
和typeof(in)
(分别)正确地返回typeof(typeof)
和typeof(in)
,因为typeof
和in
都是函数。当然,请注意typeof(typeof(typeof))
返回DataType
。
https://stackoverflow.com/questions/52351852
复制相似问题