【问题标题】:Puzzling results for Julia typeofJulia typeof 的令人费解的结果
【发布时间】:2018-09-16 07:16:03
【问题描述】:

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

# 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 documentation 表示 typeof "获取 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)

【问题讨论】:

  • 您对typeof(function)的期望是什么?即,您期望返回的值是多少?
  • 某种类型名称,函数是其类型。
  • 我不是 Julia 专家,但function 不只是开始定义函数的关键字,而不是函数本身吗?
  • typeof 对实际命名函数或匿名函数显示什么?
  • 不是function关键字是一等公民。 functions 是 Julia 中的 first-class citizensfunction 关键字不是 a 函数。您所期望的是 the 关键字 functiona 函数,但事实并非如此。甚至有些函数式编程语言没有这样的function 关键字。

标签: julia


【解决方案1】:

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

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

从 Julia v0.6+ 开始,Function 是一个抽象超类型,就像Number 是一个抽象超类型一样。所有功能,例如mean、用户定义函数和匿名函数是Function 的子类型,就像Float64IntNumber 的子类型一样。

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

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

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

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

将所有这些都与Function 超类型相关联,您会注意到typeof(sum) &lt;: Function 返回true,表明sum 的类型,即typeof(sum) 确实是Function 的子类型。还要注意typeof(typeof(sum)) 返回DataType,与typeof(typeof(1.0)) 返回DataType 的方式大致相同,这表明sum 的实际行为类似于一个值。

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

【讨论】:

  • 哇!感谢科林的出色回答。作为 Julia 的新手,这真的很有教育意义。
  • 您的回答几乎涵盖了所有内容,但仍有一点令人费解:typeof(return) 什么也没输出。也许这个原因现在对我来说应该很明显了,但事实并非如此。
  • Julia 的 JIT 编译器在 REPL 命令行上编译 typeof(return) 并在遇到 return 命令时简单地返回,从而缩短了 typeof()。
  • @Bill 谢谢比尔!我怀疑发生了类似的事情,但不确定。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-01
  • 1970-01-01
  • 2012-10-31
  • 2012-08-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多